E-mail builder library for Rust https://docs.rs/mail-builder/
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Maurus Decimus 2fc4a94275 v2.0.1
2026-11-02 09:20:45 +01:00
.github/workflows Support wasm32-unknown-unknown (#26) 2026-10-29 10:22:51 +01:00
examples v0.5.0 2026-08-18 11:34:05 +02:00
LICENSES Removed ludicrous mode 2025-01-25 18:09:31 +01:00
src Support wasm32-unknown-unknown (#26) 2026-10-29 10:22:51 +01:00
tests Support wasm32-unknown-unknown (#26) 2026-10-29 10:22:51 +01:00
.gitignore v1.0.0 2026-09-12 15:53:57 +01:00
Cargo.toml Support wasm32-unknown-unknown (#26) 2026-10-29 10:22:51 +01:00
CHANGELOG.md v2.0.1 2026-11-02 09:20:45 +01:00
README.md Support wasm32-unknown-unknown (#26) 2026-10-29 10:22:51 +01:00

mail-builder

crates.io build docs.rs crates.io

mail-builder is a flexible e-mail builder library written in Rust. It includes the following features:

  • Generates e-mail messages conforming to the Internet Message Format standard (RFC 5322).
  • Full MIME support (RFC 2045 - 2049) with automatic selection of the most optimal encoding for each message body part.
  • Fast Base64, Quoted-Printable and RFC 2047 encoding through encodify, its only required dependency (gethostname is optional).
  • Runs on wasm32-unknown-unknown with default-features = false (the clock is read through web-time on that target).

Please note that this library does not support sending or parsing e-mail messages as these functionalities are provided by the crates mail-send and mail-parser.

Usage Example

Build a simple e-mail message with a text body and one attachment:

    // Build a simple text message with a single attachment
    let eml = MessageBuilder::new()
        .from(("John Doe", "john@doe.com"))
        .to("jane@doe.com")
        .subject("Hello, world!")
        .text_body("Message contents go here.")
        .attachment("image/png", "image.png", [1, 2, 3, 4].as_ref())
        .write_to_string()
        .unwrap();
        
    // Print raw message
    println!("{}", eml);

More complex messages with grouped addresses, inline parts and multipart/alternative sections can also be easily built:

    // Build a multipart message with text and HTML bodies,
    // inline parts and attachments.
    MessageBuilder::new()
        .from(("John Doe", "john@doe.com"))

        // To recipients
        .to(vec![
            ("Antoine de Saint-Exupéry", "antoine@exupery.com"),
            ("안녕하세요 세계", "test@test.com"),
            ("Xin chào", "addr@addr.com"),
        ])

        // BCC recipients using grouped addresses
        .bcc(vec![
            (
                "My Group",
                vec![
                    ("ASCII name", "addr1@addr7.com"),
                    ("ハロー・ワールド", "addr2@addr6.com"),
                    ("áéíóú", "addr3@addr5.com"),
                    ("Γειά σου Κόσμε", "addr4@addr4.com"),
                ],
            ),
            (
                "Another Group",
                vec![
                    ("שלום עולם", "addr5@addr3.com"),
                    ("ñandú come ñoquis", "addr6@addr2.com"),
                    ("Recipient", "addr7@addr1.com"),
                ],
            ),
        ])

        // Set RFC and custom headers
        .subject("Testing multipart messages") 
        .in_reply_to(vec!["message-id-1", "message-id-2"])
        .header("List-Archive", URL::new("http://example.com/archive"))

        // Set HTML and plain text bodies
        .text_body("This is the text body!\n") 
        .html_body("<p>HTML body with <img src=\"cid:my-image\"/>!</p>") 

        // Include an embedded image as an inline part
        .inline("image/png", "cid:my-image", [0, 1, 2, 3, 4, 5].as_ref())
        .attachment("text/plain", "my fíle.txt", "Attachment contents go here.") 

        // Add text and binary attachments
        .attachment(
            "text/plain",
            "ハロー・ワールド",
            b"Binary contents go here.".as_ref(),
        )

        // Write the message to a file
        .write_to(File::create("message.eml").unwrap())
        .unwrap();

Nested MIME body structures can be created using the body method:

    // Build a nested multipart message
    MessageBuilder::new()
        .from(Address::new_address("John Doe".into(), "john@doe.com"))
        .to(Address::new_address("Jane Doe".into(), "jane@doe.com"))
        .subject("Nested multipart message")

        // Define the nested MIME body structure
        .body(MimePart::new(
            "multipart/mixed",
            vec![
                MimePart::new("text/plain", "Part A contents go here...").inline(),
                MimePart::new(
                    "multipart/mixed",
                    vec![
                        MimePart::new(
                            "multipart/alternative",
                            vec![
                                MimePart::new(
                                    "multipart/mixed",
                                    vec![
                                        MimePart::new("text/plain", "Part B contents go here...").inline(),
                                        MimePart::new(
                                            "image/jpeg",
                                            "Part C contents go here...".as_bytes(),
                                        )
                                        .inline(),
                                        MimePart::new("text/plain", "Part D contents go here...").inline(),
                                    ],
                                ),
                                MimePart::new(
                                    "multipart/related",
                                    vec![
                                        MimePart::new("text/html", "Part E contents go here...").inline(),
                                        MimePart::new(
                                            "image/jpeg",
                                            "Part F contents go here...".as_bytes(),
                                        ),
                                    ],
                                ),
                            ],
                        ),
                        MimePart::new("image/jpeg", "Part G contents go here...".as_bytes())
                            .attachment("image_G.jpg"),
                        MimePart::new(
                            "application/x-excel",
                            "Part H contents go here...".as_bytes(),
                        ),
                        MimePart::new(
                            "x-message/rfc822",
                            "Part J contents go here...".as_bytes(),
                        ),
                    ],
                ),
                MimePart::new("text/plain", "Part K contents go here...").inline(),
            ],
        ))
        
        // Write the message to a file
        .write_to(File::create("nested-message.eml").unwrap())
        .unwrap();

Testing

To run the testsuite:

 $ cargo test --all-features

to run the WebAssembly tests (requires wasm-pack and Node.js):

 $ wasm-pack test --node --no-default-features

or, to run the testsuite with MIRI:

 $ cargo +nightly miri test --all-features

License

Licensed under either of

at your option.

Copyright (C) 2020, Stalwart Labs LLC