nexacodes/email is a MoonBit email library with a small top-level facade for the common cases:
- compose plain text, HTML, or multipart messages
- derive SMTP envelopes
- encode to RFC 5322 / MIME
- send through SMTP with a small number of steps
If you only want the public surface, start from the top-level package and treat the lower packages as implementation detail.
The main facade exports:
compose_plain_textcompose_htmlcompose_mixedenvelope_forsend_plain_textsend_htmlsend_mixedto_rfc5322parse_rfc5322render_to_rfc5322
It also re-exports the common data types you need at the call site, such as:
MailboxBodyMessageEnvelopeSmtpConfigSmtpTransportFakeTransportFileTransport
For a low-ceremony compose flow:
// assuming you import the `nexacodes/email` facade package
///|
let from = Mailbox::new("sender@example.com", Some("Sender")) |> must_ok
///|
let to = Mailbox::address_only("reader@example.com") |> must_ok
///|
let message = compose_plain_text(from, [to], "Greetings", "Hello from MoonBit!")
|> must_ok
///|
let envelope = envelope_for(message) |> must_ok
///|
let encoded = to_rfc5322(message)For a one-step SMTP send:
///|
let config = SmtpConfig::new(
"smtp.example.com",
465,
security=SmtpSecurity::Tls,
auth=SmtpAuth::Plain("sender@example.com", "app-password"),
)
///|
let outcome = send_plain_text(
config,
from,
[to],
"Greetings",
"Hello from MoonBit!",
)
|> must_oksend_plain_text, send_html, and send_mixed return Result[..., ValidationError] for message construction failures. SMTP protocol and connection failures remain the responsibility of the transport layer.
For multipart mail with attachments:
///|
let attachment = Body::attachment_file(
"report.pdf",
"/path/to/report.pdf",
content_type=infer_content_type("report.pdf"),
)
|> must_ok
///|
let message = compose_mixed(from, [to], "Monthly report", [
Body::plain_text("See attachment."),
attachment,
])
|> must_okIf you want to send that style of message in one step, use send_mixed.
For unit tests, use FakeTransport:
let transport = FakeTransport::new()
let outcome = transport.send_message(envelope, message) |> must_okFor local .eml output, use FileTransport.
For real delivery, use SmtpTransport.
The repository includes a runnable example in cmd/main/main.mbt.
It demonstrates:
- QQ SMTP over TLS
- repeated
--attachmentarguments - file-backed attachment sending through
SmtpTransport
moon run cmd/main -- \
--sender your-account@example.com \
--recipient someone@example.com \
--auth-code your-auth-code \
--subject "MoonBit email test" \
--body "Hello from nexacodes/email"Available today:
- top-level facade helpers for compose and send flows
- MIME render and parse support
- in-memory and file-backed attachments
- fake, file, and real SMTP transports
Still evolving:
- higher-level extension features under
ext - provider-specific integrations
Architecture notes remain available in docs/architecture.md if you want the lower-level package boundaries and design rationale.
moon check
moon test
moon info
moon fmt