Simple Java Mail

website·Indexed 33 days ago

https://www.simplejavamail.org/

A high-level Java library for sending emails, built on top of Jakarta Mail. It provides a fluent API using the Builder pattern (EmailBuilder and MailerBuilder) to compose emails with text, HTML, attachments, and calendar components. Features include SMTP connection pooling, S/MIME encryption, DKIM, OAuth2 authentication, and a CLI for terminal commands. Supports Java 8+ and is available via Maven Central.

Tokens
27.7K
Snippets
145
Records
185
Agent score
67%

What's inside Simple Java Mail

  1. Overview of Simple Java Mail

    Simple Java Mail (SJM) is a high-level library built on top of Jakarta Mail. It abstracts the low-level 'plumbing' of email—such as MIME structures, session properties, and transport cleanup—into a usable API. While Jakarta Mail provides the standards-aware foundation, SJM adds capabilities for reusable message rules, DKIM, S/MIME, diagnostics, authenticated SOCKS proxies, and batched, pooled, or clustered delivery.
  2. Understand Jakarta Mail / Angus Mail capabilities and limitations

    Jakarta Mail (and its implementation Angus Mail) is a standard low-level foundational SDK used for handling MIME messages and SMTP transport. It is a low-level SMTP toolkit and does not provide built-in support for the following advanced features: DKIM, S/MIME, connection pooling, or batch delivery.
  3. Build MIME-compliant email messages with Simple Java Mail

    Simple Java Mail automates the construction of the MIME tree required by email clients. Instead of manually assembling multipart nesting, content IDs, transfer encoding, and transport plumbing, developers can simply declare the desired message components—such as plain text, HTML, inline images, attachments, or calendar events—and the library handles the underlying structure.
  4. Migrate to Simple Java Mail 6.0.0 modular architecture

    Simple Java Mail 6.0.0 has transitioned to a modular system to better manage 3rd party dependencies and improve maintainability. The project is now divided into a core module (containing the builder API and interfaces) and various optional modules.

    Key Changes:

    • Dependency Management: You should no longer manually include 3rd party dependencies in Maven; instead, include the specific Simple Java Mail module that provides the required functionality. Each optional module now manages its own 3rd party dependencies.
    • Package Changes: Many packages have been renamed and classes have been moved to align with the new modular structure.
  5. Sign and encrypt emails with S/MIME

    Simple Java Mail supports S/MIME signing and encryption. If both are used, the email is signed first and then encrypted. Encryption can be configured at the email level, mailer level, or per-recipient. If a recipient has a specific certificate, it is used; otherwise, the system falls back to the email-level or mailer-level SmimeEncryptionConfig. For groups of recipients, RecipientsBuilder can be used to manage certificate rules (e.g., withDefaultSmimeCertificate or withFixedSmimeCertificate).
  6. Automatic MIME structure assembly with Simple Java Mail

    While Jakarta Mail provides the low-level building blocks (MimeMessage, MimeBodyPart, and MimeMultipart), the developer is typically responsible for the nesting logic. Simple Java Mail abstracts this by automatically selecting the correct MIME structure based on the declared content (plain text, HTML, embedded resources, calendar data, attachments, or forwarded messages). It automatically handles the necessary body parts, content IDs, dispositions, and encodings required for the chosen structure.
  7. Load configuration properties programmatically

    Use ConfigLoader.loadProperties to load configuration from files or Properties objects. System properties and environment variables maintain priority over these loaded values. Load all configuration sources before creating the MailerBuilder and Mailer instance.
    // Load from a specific file path
    Path environmentConfig = Path.of("config", "candystore", "simplejavamail.properties");
    ConfigLoader.loadProperties(Files.newInputStream(environmentConfig), false);
    
    // Load from a classpath resource with override flag
    ConfigLoader.loadProperties("special-override.properties", true);
    
    // Load from a java.util.Properties object
    Properties runtimeOverrides = new Properties();
    runtimeOverrides.setProperty("simplejavamail.smtp.port", "2525");
    ConfigLoader.loadProperties(runtimeOverrides, true);
    
    // Build the mailer after all configs are loaded
    Mailer mailer = MailerBuilder
                      .withSMTPServerPort(587)
                      .withTransportStrategy(TransportStrategy.SMTP_TLS)
                      .buildMailer();
  8. Set custom email headers

    Add custom headers to an email using withHeader for individual entries or withHeaders to provide a map of headers. This is useful for priority flags, campaign tracking, or specific server requirements.
    currentEmailBuilder
        .withHeader("X-Priority", 2)
        .withHeader("X-MC-GoogleAnalyticsCampaign", "halloween_sale")
        .withHeader("X-my-custom-header", "foo")
        // or
        .withHeaders(yourHeadersMap);
  9. Encrypt emails using S/MIME

    S/MIME encryption can be applied at the email level using a fallback certificate, or at the recipient level for granular control. If a recipient has a specific certificate assigned via RecipientBuilder, it takes precedence over the email-level fallback certificate.
    // 1. Email-level encryption (fallback)
    Email emailToBeEncrypted = currentEmailBuilder
        .encryptWithSmime(SmimeEncryptionConfig.builder()
    		.x509Certificate("x509CertificateInStandardPEM.crt")
    		.keyEncapsulationAlgorithm("RSA_OAEP_SHA384") // optional
    		.cipherAlgorithm("AES256_CBC") // optional
    		.build())
        .buildEmail();
    
    // 2. Recipient-specific encryption
    Recipient alice = new RecipientBuilder()
        .withAddress("alice@example.com")
        .withSmimeCertificate(aliceCertificate)
        .build();
    
    Email emailWithSpecificCerts = currentEmailBuilder
        .withRecipients(alice)
        .encryptWithSmime(algorithmsAndFallback)
        .buildEmail();
  10. Send emails in batches or with open connections

    For improving performance by reducing connection overhead, Simple Java Mail provides sequential batch sending and scoped open connections.

    • sendMailsInSimpleBatch: Sends multiple emails sequentially over a single SMTP connection.
    • withOpenConnection: Keeps one SMTP connection open for a callback, allowing the caller to manage the queue and perform custom logic between sends.
    // Simple batch sending
    mailer.sendMailsInSimpleBatch(emails);        // uses mailer's async default
    mailer.sendMailsInSimpleBatch(emails, false); // blocks until batch is done
    mailer.sendMailsInSimpleBatch(emails, true);  // schedules batch asynchronously
    
    // Scoped open connection for custom queue management
    mailer.withOpenConnection(sender -> {
        while (database.hasPendingMail()) {
            Email next = database.nextPendingMail();
            sender.sendMail(next);
            database.markSent(next);
        }
    });
  11. Sign emails using S/MIME

    To sign an email with S/MIME, use SmimeSigningConfig with a Pkcs12Config object containing the keystore details. You can apply this to a specific email via the EmailBuilder or set it as a default for all emails sent by a mailer.
    Pkcs12Config myKeyInfo = Pkcs12Config.builder()
        .pkcs12Store("my_smime_keystore.pkcs12")
        .storePassword("my_store_password")
        .keyAlias("my_key_alias")
        .keyPassword("my_key_password")
        .build();
    
    Email emailToBeSigned = currentEmailBuilder
        .signWithSmime(SmimeSigningConfig.builder()
    		.pkcs12Config(myKeyInfo)
    		.signatureAlgorithm("SHA256withRSA") // optional
    		.build())
        .buildEmail();
    
    mailer.sendMail(emailToBeSigned);
  12. Ignore or exclude defaults and overrides for specific emails

    If a specific email should not use the configured defaults or overrides, use the ignoringDefaults() and ignoringOverrides() methods. You can also exclude specific properties using dontApplyDefaultValueFor or dontApplyOverrideValueFor.
    // Completely ignore defaults and overrides
    Email email = EmailBuilder.startingBlank()
        .ignoringDefaults()
        .ignoringOverrides()
        .buildEmail();
    
    // Exclude specific fields from being applied
    emailBuilder
        .dontApplyDefaultValueFor(EmailProperty.FROM_RECIPIENT, EmailProperty.REPLYTO_RECIPIENT)
        .dontApplyOverrideValueFor(EmailProperty.DKIM_SIGNING_CONFIG);