Simple Java Mail Documentation

repository·master·Indexed 23 days ago

https://github.com/bbottema/simple-java-mail

A high-level Java mailing library built on top of Angus Mail (formerly Jakarta Mail) designed to simplify sending emails in Java applications. It provides a consistent API for complex tasks including rich content support, DKIM/S/MIME signing and encryption, high-throughput batch sending, and Spring configuration, while maintaining Java 8 compatibility.

Tokens
10.8K
Snippets
11
Records
55
Agent score
79%

What's inside Simple Java Mail

  1. Overview of Simple Java Mail features

    master

    Simple Java Mail is a high-level Java mailing library built on top of Angus Mail (formerly Jakarta Mail). It provides a consistent API for complex mailing tasks while maintaining Java 8 compatibility.

    Core Capabilities:

    • Content: Rich content support, pre-encoded attachments, and embedded images.
    • Security: Signing (DKIM, S/MIME) and encryption.
    • Governance: Recipient governance and per-recipient S/MIME certificates.
    • Transport: Transport security, high-throughput batch sending, and clustered sending.
    • Reliability: Diagnostics, validation, and Delivery Status Notification (DSN) support.
    • Extensibility: Fluent builders, Spring configuration, and access to lower-level Jakarta Mail escape hatches.
  2. Understand Nullability and CLI Optionality

    master

    Simple Java Mail uses JetBrains @NotNull and @Nullable annotations for both API safety and runtime validation.

    API Usage

    • Do not treat nullability annotations as cosmetic; they affect generated bytecode and runtime validation.

    CLI Integration

    If you are extending the library's CLI capabilities:

    • The CLI uses @Cli.Optional to determine if a command argument is optional.
    • The BuilderApiToPicocliCommandsMapper marks CLI parameters as required unless they are explicitly annotated with @Cli.Optional.
    • When adding new public builder API nullability, if you want the CLI to reflect that change, you must add both @Nullable and @Cli.Optional.
  3. Encoding and decoding behavior for MIME headers

    master

    To prevent issues with non-ASCII characters and header injection, the library follows these rules regarding data encoding:

    • Model Values: All values stored in the Email model (filenames, Content-IDs, descriptions) are kept decoded and human-meaningful.
    • Encoding: Encoding (e.g., RFC-2047) occurs only at the MIME output boundaries (when the email is being sent).
    • Decoding: Decoding occurs at the MIME parse boundaries (when an email is being received) before the data is validated or populated into the model.
    • Security: The library performs CRLF/header-injection checks on the decoded values to ensure security.
  4. Understand attachment identifiers: Filename vs Content-ID

    master

    Attachments in Simple Java Mail use two distinct identifiers:

    1. Visible/Download Filename: The name the user sees. The fallback order is:

      • Explicit AttachmentResource.getName()
      • DataSource.getName()
      • Generated resource<UUID>
    2. MIME Content-ID: The internal MIME header.

      • If an explicit AttachmentResource.getContentId() is provided, it is used.
      • If not provided, the library generates an opaque, transport-only ID in the format sjm-<UUID>@simplejavamail.generated. This prevents collisions and ensures that multiple attachments with the same name are treated as distinct parts.
  5. Manage attachment and resource naming priority

    master

    The library follows a strict hierarchy for naming resources (attachments and embedded images) to prevent unexpected overrides from underlying data sources (like File or URL datasources):

    1. Explicit API Names: These are the strongest and always take precedence.
    2. Datasource Names: These are treated as fallback metadata only. If you provide an explicit name via the API, the name returned by DataSource.getName() will be ignored for the outgoing MIME output.

    Note: Because explicit names override datasource names, you should not assume that a round-trip (sending and then parsing the email back) will recover the original datasource name.

  6. Use dynamic embedded image resolution

    master

    If your HTML contains image sources that do not use the cid: protocol (e.g., standard file paths or URLs), the builder can automatically resolve them. The builder will:

    1. Resolve the image from file, classpath, or URL settings.
    2. Generate a random CID.
    3. Add the image as an embedded resource.
    4. Rewrite the HTML to use the new cid:<generated> reference.
  7. How CLI generation from Builder API Javadocs works

    master

    The Command Line Interface (CLI) is automatically generated from the Java Builder API. This ensures near one-to-one feature parity between the Java API and the CLI, including synchronized documentation. The process uses reflection and Therapi to bake Javadocs into runtime-readable classes.

    CLI Compatibility Rules

    A builder method is automatically converted into a CLI option if it meets these criteria:

    • It is on a builder API node annotated with @Cli.BuilderApiNode.
    • It is not annotated with @Cli.ExcludeApi.
    • It is not a bean accessor.
    • It does not take collection parameters.
    • It is convertible from string arguments.

    Customizing CLI Behavior

    • Excluding Methods: Use @Cli.ExcludeApi(reason = "...") for methods that are not CLI-compatible (e.g., complex objects or ambiguous overloads).
    • Overriding Names: Use @Cli.OptionNameOverride to resolve name collisions or provide a specific CLI name.
    • Optional Parameters: Explicitly mark optional CLI parameters with @Cli.Optional. Note that @Nullable is used for the Java API contract, but @Cli.Optional drives the CLI metadata.
    • New Types: If you introduce a new string-convertible type, you must register a value converter in BuilderApiToPicocliCommandsMapper.
  8. How embedded images and Content-IDs are handled

    master

    When working with embedded images, the library distinguishes between the resource name (used for filename/metadata) and the Content-ID (used for HTML referencing).

    To ensure correct rendering:

    • Use withEmbeddedImage(name, dataSource): The HTML must reference this as cid:name (without angle brackets).
    • Use withEmbeddedImage(name, dataSource, contentId): The HTML must reference this as cid:contentId. In this case, name is treated as metadata (like a filename) and does not affect the CID.
    • Important: The library ensures that filename extension repairs or datasource name fallbacks do not mutate the Content-ID. The Content-ID remains exactly what was provided via the API.
  9. How inline-versus-attachment classification works on receive

    master

    When parsing received emails, the library does not rely solely on the Content-Disposition header to classify a body part, as this header can be unreliable. Instead, it uses a combination of signals:

    1. Content-ID: The presence of a Content-ID is a primary signal.
    2. HTML References: If a Content-ID is referenced in the HTML body using the cid: prefix, the library treats that part as an embedded resource.
    3. Dual Classification: A body part can be classified as both an attachment and an embedded image if the MIME source specifies attachment but the HTML references its Content-ID.

    If a resource has a Content-ID but is not referenced anywhere in the HTML, it is treated as a regular attachment.

  10. Integrate new fields with EmailGovernance (Defaults & Overrides)

    master

    To allow projects to centralize behavior through default or override Email objects, new user-facing fields in the Email model should be integrated with the governance layer. This provides parity between the Java builder API and the defaults/overrides mechanism.

    Workflow for Governance Integration:

    1. Add EmailProperty: Add a constant to org.simplejavamail.internal.config.EmailProperty in the core-module. Mark it as collection-based if the value is a collection to enable merging instead of replacement.
    2. Apply Default Values: In EmailGovernanceImpl.newDefaultsEmailWithDefaultDefaults(), derive a sensible default from ConfigLoader.Property and set it on the builder.
    3. Apply Defaults/Overrides: In EmailGovernanceImpl.produceEmailApplyingDefaultsAndOverrides(), resolve values using MiscUtil.overrideOrProvideOrDefaultProperty or overrideAndOrProvideAndOrDefaultCollection and apply them to the builder.

    When to skip governance integration:

    • If the value cannot be represented on the source model.
    • If it depends on runtime state that cannot be copied.
    • If it is a per-recipient sub-field (these should be set via IRecipientsBuilder / RecipientsBuilder instead).
  11. How Smart MIME Message Structure Selection works

    master

    To optimize performance and complexity, Simple Java Mail selects the most efficient MIME producer based on the content of the email. It evaluates three dimensions:

    1. Mixed content: Presence of attachments or forwarded emails.
    2. Related content: Presence of embedded images.
    3. Alternative content: Presence of multiple body variants (e.g., both Plain Text and HTML).

    Producer Selection Matrix

    MixedRelatedAlternativeResulting Producer
    nononoMimeMessageProducerSimple
    nonoyesMimeMessageProducerAlternative
    noyesnoMimeMessageProducerRelated
    yesnonoMimeMessageProducerMixed
    yesyesnoMimeMessageProducerMixedRelated
    yesnoyesMimeMessageProducerMixedAlternative
    noyesyesMimeMessageProducerRelatedAlternative
    yesyesyesMimeMessageProducerMixedRelatedAlternative

    Post-Selection Wrapping

    After the structure is created, the following wrappers are applied in order:

    1. S/MIME signing
    2. S/MIME encryption
    3. DKIM signing
    4. Bounce-to wrapping

    Note: If you request DKIM or S/MIME, the respective modules must be on the runtime classpath.

  12. How receiving and parsing works

    master

    The parser is designed to be permissive to handle variations in how different email clients (Gmail, Outlook, etc.) structure messages. Key parsing behaviors include:

    • CID Mapping: Any body part with a Content-ID can be entered into the CID map.
    • Attachment Detection: A body part is treated as an attachment if it lacks an inline disposition or lacks a Content-ID.
    • Name Priority: A real filename takes precedence as the resource name. The Content-ID is only used as a fallback name if the filename is missing.
    • Cleanup: After parsing, any CID-map entries that are not actually referenced by a cid: tag in the HTML are moved to the attachments list.
    • Dual Role: A part can be both a downloadable attachment (via Content-Disposition: attachment) and an embedded resource if the HTML references its Content-ID.