March Docs

Marathon.Adapters.Smtp

SMTP adapter: a real RFC 5321 client (no vendor HTTP API dependency). build_envelope is PURE (headers + dot-stuffed body, no sockets) so it's unit-tested without a network, mirroring Adapters.Mailgun.build_request. deliver (Task 4) performs the actual EHLO/STARTTLS/AUTH/MAIL FROM/RCPT TO/DATA handshake.

Functions

fnauth_login_commandsauth_login_commands(user : String, pass : String)#

Base64-encode the username/password for AUTH LOGIN's two-step challenge/response.

fnbuild_envelopebuild_envelope(email)#

Build the SMTP envelope (MAIL FROM address, RCPT TO addresses including Bcc, and the full DATA payload with dot-stuffing applied) from an Email. Pure — performs no network I/O.

fncheck_responsecheck_response(io, expected : String) : Result((), String)#

Read one SMTP response line via io.read and check its 3-digit status code is expected. SMTP multi-line responses use \

fndeliverdeliver(email, cfg)#

Deliver an Email over real SMTP: connect, EHLO, STARTTLS, AUTH LOGIN, MAIL FROM, RCPT TO (one per recipient incl. Bcc), DATA. cfg.host must be non-empty. cfg.ca_file: Option(String) — None trusts the system default CA store (the normal production case); Some(path) trusts a specific CA/ self-signed cert instead (private relays, or tests against a fake server). Returns Ok("smtp") on success, Err(reason) otherwise.

**KNOWN BROKEN IN COMPILED MODE:** calling this in a `--compile`d binary
SIGSEGVs today, deterministically, on the first `Tls.write` after a
successful STARTTLS handshake — a March compiler bug, not a bug in this
adapter (`lib/tir/llvm_emit.ml:827` misdeclares `Tls.write`'s return type
as `TUnit` instead of the `Result(Int, String)` it actually returns, so
codegen dereferences a fabricated fake pointer instead of the real
returned value). This is not a cosmetic or "worth fixing eventually"
issue: it is a blocking defect that makes `deliver`'s real-transport path
(`deliver_over_fd` → `tls_io`) presently non-functional end-to-end when
compiled. It does NOT affect the interpreter, and it does NOT affect the
command-sequence logic itself (`check_response`/`send_cmd`/`send_rcpts`/
`send_envelope`/`deliver_over_tls`), which is transport-agnostic and fully
covered via the in-memory fake `io` in `test/marathon_test.march`. Do not
rely on this adapter for real compiled delivery until the upstream
compiler bug is fixed — tracked as a compiler-level defect, out of this
library's scope to fix directly (see the module-level comment above
`check_response` for full root-cause detail).
fndeliver_over_tlsdeliver_over_tls(io, cfg, env) : Result(String, String)#

EHLO / AUTH LOGIN / <envelope> — the post-STARTTLS command sequence, generic over io (see the module-level note above).

fnsend_cmdsend_cmd(io, cmd : String) : Result((), String)#

Send one SMTP command line (CRLF-terminated) via io.write.

fnsend_envelopesend_envelope(io, env) : Result(String, String)#

MAIL FROM / RCPT TO* / DATA / <payload> — the envelope-delivery tail of the handshake, once EHLO+AUTH have succeeded.

fnsend_rcptssend_rcpts(io, rcpts : List(String)) : Result((), String)#

Send a RCPT TO command for each recipient, checking for a 250 after each.