Skip to content
DemoSampleAPI ReferenceFAQ

PDF Generation Template Editor

Open-source visual PDF generation engine with customizable templates and developer-friendly APIs.

View on GitHub

Convert Email to HTML and PDF ​

Formats and Initialization ​

Version 1.3.0 introduces the CEmailConverter API for EML/MIME messages and Outlook MSG files. It supports file paths, File objects, byte arrays and input streams, and can generate an HTML package or a PDF containing the email body and an optional attachment list.

Use the matching version of the JAR and native library. Before running the PDF examples below, initialize the SDK with a valid license as described in Apply the License Key. HTML parsing and HTML-package export do not require a license, but the native library must still be loaded; for an HTML-only application, System.load() can load the matching native library by its absolute path.

CEmailFormat provides EMAIL_FORMAT_AUTO, EMAIL_FORMAT_EML and EMAIL_FORMAT_MSG. AUTO identifies MSG from its Compound File Binary signature and otherwise parses the input as EML; it does not rely on the filename extension. Pass binary MSG data directly rather than converting it to a Java string.

Convert an Email File to PDF ​

java
import CPDFGeneration.CEmailConverter;
import CPDFGeneration.CEmailDiagnostic;
import CPDFGeneration.CEmailResult;

try (CEmailResult result = CEmailConverter.ConvertToPdf("message.eml", "message.pdf")) {
    if (!result.isSuccess()) {
        for (int i = 0; i < result.GetDiagnosticCount(); i++) {
            CEmailDiagnostic diagnostic = result.GetDiagnostic(i);
            System.err.println(diagnostic.code + ": " + diagnostic.detail);
        }
        throw new IllegalStateException("Email conversion failed: " + result.GetStatus(),
                result.GetLastCallbackException());
    }
    System.out.println("Converted format: " + result.GetFormat());
}

The same example accepts an MSG input by replacing message.eml with a MSG path. The output PDF must not already exist: path output preserves existing files and removes a partial file created by the operation if it fails. Always close the returned CEmailResult, including on failure. Both EMAIL_SUCCESS and EMAIL_SUCCESS_WITH_WARNINGS are successful; isSuccess() accepts either.

The PDF contains the selected email body and, when enabled, an attachment list. It does not embed attachment files or render attachment contents as additional pages. Attachment download links are omitted from the PDF; use HTML-package export or attachment data access when you need the files.

Export HTML and Write PDF in Separate Steps ​

Parse once with ConvertToHtml(), then export an offline HTML package or write a PDF from the retained content. This example also queries the selected primary body's provenance and applies custom page margins.

java
import CPDFGeneration.CConverterProperties;
import CPDFGeneration.CEmailBodySource;
import CPDFGeneration.CEmailConverter;
import CPDFGeneration.CEmailResult;
import CPDFGeneration.CEmailStatus;

CConverterProperties properties = new CConverterProperties();
try {
    properties.setPageMargins(48, 40, 48, 40);
    try (CEmailResult result = CEmailConverter.ConvertToHtml("message.msg")) {
        if (!result.isSuccess()) {
            throw new IllegalStateException("Email parsing failed: " + result.GetStatus());
        }
        CEmailBodySource body = result.GetSelectedBodySource();
        if (body.status.isSuccess()) {
            System.out.println(body.mediaType + " / " + body.origin);
        }
        CEmailStatus exported = result.ExportHtml("mail-package");
        if (!exported.isSuccess()) {
            throw new IllegalStateException("HTML export failed: " + exported);
        }
        CEmailStatus written = result.WritePdf("message.pdf", properties);
        if (!written.isSuccess()) {
            throw new IllegalStateException("PDF write failed: " + written,
                    result.GetLastCallbackException());
        }
    }
} finally {
    properties.release();
}

Use a new output directory for the HTML package. ExportHtml() writes index.html, body resources and enabled attachments without overwriting existing output files. Failure removes files created by that export, while preserving caller data. GetHtml() returns only the UTF-8 HTML string, which may contain relative resource paths; use ExportHtml() to obtain a complete offline package.

Check the status returned by each export/write operation. GetStatus() describes the latest operation and can replace the original conversion status. Each new native output operation recalculates status and diagnostics from the initial HTML conversion state. Previously obtained Java snapshots remain valid.

PDF, license or output failures can retain successfully generated HTML, resources and attachments, allowing a later export or PDF retry. An input parsing failure does not guarantee that HTML exists. GetSelectedBodySource().status describes the provenance query only and does not change the result's operation status. It identifies the selected primary body, not every displayed multipart segment; its source IDs are opaque within that result. The returned CEmailBodySource contains bodyId, sourceId, mediaType and origin; the media type is text/plain or text/html, and the origin is original, recovered, fallback or generated.

When PDF properties are null, email conversion uses A4 with top/bottom margins of 32 CSS px and left/right margins of 40 CSS px. A supplied properties object preserves its configured page size, margins (including zero), font provider and header/footer settings. The operation does not modify the caller's properties or base URI. HTML-preview padding is not added to PDF page margins. See Page Margins and Headers and Footers for print configuration.

Options and Cancellation ​

Pass null options for defaults, or create a CEmailOptions object. Options are copied when conversion begins; do not modify them concurrently while the copy is being made.

FieldDefaultDescription
flags7Include headers, show the attachment list and enable attachment export.
maxInputBytes100 MiBMaximum input size in bytes.
maxDecodedBytes256 MiBDecoded-content byte budget.
maxHtmlBytes64 MiBGenerated HTML byte budget.
cancellationCallbacknullOptional CEmailCancelCallback returning true to request cancellation.

Combine CEmailFlags values with bitwise OR:

FlagEffect
EMAIL_INCLUDE_HEADERSDisplay the email header summary. Enabled by default.
EMAIL_INCLUDE_ATTACHMENT_LISTDisplay an attachment list. Enabled by default.
EMAIL_EXPORT_ATTACHMENTSExport available attachment files with the HTML package. Enabled by default.
EMAIL_INLINE_RESOURCESInline body resources in the generated HTML.
EMAIL_RECOVER_EMLEnable bounded recovery of malformed EML; inspect diagnostics for fallback or skipped content.
EMAIL_INCLUDE_BCCDisplay Bcc, which is hidden by default.
java
import CPDFGeneration.CEmailConverter;
import CPDFGeneration.CEmailFlags;
import CPDFGeneration.CEmailFormat;
import CPDFGeneration.CEmailOptions;
import CPDFGeneration.CEmailResult;
import java.util.concurrent.atomic.AtomicBoolean;

CEmailOptions options = new CEmailOptions();
options.flags |= CEmailFlags.EMAIL_INLINE_RESOURCES;
options.maxInputBytes = 20L * 1024 * 1024;
AtomicBoolean cancelled = new AtomicBoolean(false);
options.cancellationCallback = cancelled::get;
try (CEmailResult result = CEmailConverter.ConvertToHtml(
        "message.eml", CEmailFormat.EMAIL_FORMAT_AUTO, options)) {
    if (!result.isSuccess()) {
        throw new IllegalStateException("Email parsing failed: " + result.GetStatus(),
                result.GetLastCallbackException());
    }
    System.out.println("HTML characters: " + result.GetHtml().length());
}

Byte budgets are nonnegative; zero is a real zero limit, not unlimited. Negative budgets throw IllegalArgumentException when passed to a converter. Unknown flag bits produce EMAIL_ERROR_INVALID_PARAMETER. Internal parser/structural limits also apply, even when the configured byte budgets have not been exceeded.

Cancellation is cooperative, checked between phases and during callback I/O. It does not interrupt a parser or layout operation already in progress and does not provide a hard timeout. The callback runs synchronously on the calling Java thread and must return promptly. Another thread can request cancellation by setting the example's cancelled flag to true.

The result retains the callback for subsequent ExportHtml() and WritePdf() calls until the result is closed. Changing the original options object does not replace that retained callback. A callback exception is treated as cancellation and is available through GetLastCallbackException(). Do not reenter SDK operations, close the active result, release its properties or synchronously wait for another PDF task from the callback.

Stream and Memory Input ​

For an input stream, supply the number of email bytes to read from its current position. Do not use InputStream.available() as the message length. For a file, use Files.size() and ensure that the input does not change while it is read.

java
import CPDFGeneration.CEmailConverter;
import CPDFGeneration.CEmailResult;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

Path input = Paths.get("message.eml");
Path output = Paths.get("message-stream.pdf");
long length = Files.size(input);
try (InputStream source = Files.newInputStream(input);
     OutputStream destination = Files.newOutputStream(output,
             StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE);
     CEmailResult result = CEmailConverter.ConvertToPdf(source, length, destination)) {
    if (!result.isSuccess()) {
        throw new IllegalStateException("Stream conversion failed: " + result.GetStatus(),
                result.GetLastCallbackException());
    }
}

Short reads are retried. Premature EOF produces EMAIL_ERROR_READ with the original EOFException retained by the result. SDK operations do not close or flush caller streams; the try-with-resources block above closes them on the caller's behalf. On failure or cancellation, discard partial output, including a file created by the caller for the output stream.

To work entirely in memory:

java
import CPDFGeneration.CEmailConverter;
import CPDFGeneration.CEmailResult;
import java.io.ByteArrayOutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;

byte[] email = Files.readAllBytes(Paths.get("message.msg"));
ByteArrayOutputStream output = new ByteArrayOutputStream();
try (CEmailResult result = CEmailConverter.ConvertToPdf(email, output)) {
    if (!result.isSuccess()) {
        throw new IllegalStateException("Memory conversion failed: " + result.GetStatus(),
                result.GetLastCallbackException());
    }
    byte[] pdf = output.toByteArray();
    System.out.println("PDF bytes: " + pdf.length);
}

Memory input and output consume Java heap space. For large messages, prefer file or stream input and avoid copying attachment payloads unless they are needed.

The following overload groups provide both convenience methods and full methods with explicit format/options. PDF methods also accept CConverterProperties:

OperationInputOutputAdditional full-method parameters
ConvertToHtmlString path or FileCEmailResultCEmailFormat, CEmailOptions
ConvertToHtmlbyte[]CEmailResultCEmailFormat, CEmailOptions
ConvertToHtmlInputStream, long lengthCEmailResultCEmailFormat, CEmailOptions
ConvertToPdfString pathString PDF pathCEmailFormat, CEmailOptions, CConverterProperties
ConvertToPdfFileFile PDF outputCEmailFormat, CEmailOptions, CConverterProperties
ConvertToPdfbyte[]OutputStreamCEmailFormat, CEmailOptions, CConverterProperties
ConvertToPdfInputStream, long lengthOutputStreamCEmailFormat, CEmailOptions, CConverterProperties

Convenience methods use AUTO format and default options. Convenience PDF methods also use default email page properties. All converter methods return an owned CEmailResult that must be closed.

Result Data and Status Codes ​

Result methodPurpose
GetStatus() / isSuccess()Status of the latest conversion or native output operation.
GetFormat()Input format reported by the parser.
GetPdfError()Underlying CHtmlConverter.CErrorCode for PDF/license failures.
GetHtml()HTML string, or an empty string if HTML was not generated.
GetResourceCount() / GetResource(index)Body-resource count and metadata/payload snapshots.
GetAttachmentCount() / GetAttachment(index)Attachment count and metadata/payload snapshots.
GetDiagnosticCount() / GetDiagnostic(index)Error/warning diagnostics, including code, source ID, detail and fallback action.
GetSelectedBodySource()Selected primary body's query status, IDs, media type and origin.
GetLastCallbackException()Captured Java stream/cancellation exception, or null.
ExportHtml(String / File)Export an offline HTML package.
WritePdf(String / File / OutputStream [, properties])Generate or retry PDF from retained HTML.

GetResource() returns CEmailResource; GetAttachment() returns CEmailAttachment; GetDiagnostic() returns CEmailDiagnostic. Resources and attachments provide metadata such as media type, relative path and size. Attachments also expose id, originalName, displayName, hasData, hidden, referencedByBody and nestedMessage. A metadata-only attachment has hasData == false and getData() == null, unlike a valid zero-byte attachment.

Collection indices are zero-based; an invalid index throws IndexOutOfBoundsException. Metadata and payload snapshots are Java-owned copies that remain valid after the result is closed. Each getData() call returns another independent byte-array copy, so large payloads require additional heap space.

CEmailStatusValueMeaning
EMAIL_SUCCESS0Success without warnings.
EMAIL_SUCCESS_WITH_WARNINGS1Success with warnings or fallback content.
EMAIL_ERROR_INVALID_PARAMETER-1Invalid argument, format or option.
EMAIL_ERROR_READ-2Input read failure.
EMAIL_ERROR_PARSE-3Email parsing failure.
EMAIL_ERROR_HTML-4HTML generation failure.
EMAIL_ERROR_WRITE-5Output write failure.
EMAIL_ERROR_PDF-6PDF rendering failure.
EMAIL_ERROR_LICENSE-7PDF license check failed.
EMAIL_ERROR_LIMIT-8A byte budget or internal structural limit was exceeded.
EMAIL_ERROR_CANCELLED-9Cancellation requested.
EMAIL_ERROR_OUT_OF_MEMORY-10Native allocation failure.
EMAIL_ERROR_INTERNAL-11Internal error or unknown native status.

Typical conversion failures are reported as statuses. Java-side argument validation, such as negative budgets or a path containing NUL, can throw IllegalArgumentException; Java/JNI allocation failures can throw OutOfMemoryError. Stream and cancellation exceptions are retained by GetLastCallbackException(), and that value is replaced by the next native output operation. A Java validation failure leaves the previous operation state intact.

Resource Lifetime and Concurrency ​

  • Use try-with-resources for every CEmailResult. close() and release() are idempotent; native queries/output after closing throw IllegalStateException. isClosed() remains available.
  • Keep supplied converter properties and their font provider valid and unchanged during conversion. Email operations borrow properties under the same lock used by release(); released properties cannot be reused with the email API.
  • Independent results can be parsed or exported concurrently. Operations and close on the same Java result are serialized.
  • Email PDF rendering is serialized internally. Do not render concurrently through the older HTML API or change global license/font state while PDF rendering is active.
  • Respect the callback restrictions in Options and Cancellation to avoid reentry or waiting on an active conversion.
  • Java paths and metadata use UTF-8. Linux JDK 8 also requires a UTF-8 filesystem locale for paths containing non-ASCII characters.

Email Sample ​

Run the packaged example from the samples directory:

bash
cd EmailConvertTest
bash RunTest.sh

The example reads the fixed EML/MSG inputs directly from samples/TestFiles/email, and writes an HTML package, a PDF with headers/footers, a nested-message PDF and a stream-generated PDF to a new samples/out/email-example-* directory. On Linux, its script locates and preloads libjsig.so from the Java installation on PATH to preserve JVM signal-handler behavior. Cached online-license background refresh remains enabled by default.

PrintOptionsTest demonstrates page margins and header/footer configuration. FamilyHeaderFooterTest demonstrates cover-page handling and page numbering with TestFiles/family_html/family_all_pages.html.