NAME
std/net/smtp - low-level mail delivery.
SYNOPSIS
from std/net/smtp import Mailer, MailResult;
let headers := new PairList();
headers.add( "From", "sender@example.test" );
headers.add( "To", "recipient@example.test" );
headers.add( "Subject", "Example" );
headers.add( "Message-ID", "<example-1@example.test>" );
let mailer := new Mailer(
transport: "smtp",
host: "127.0.0.1",
port: 2525
);
let result := mailer.send(
"sender@example.test",
[ "recipient@example.test" ],
headers,
to_binary( "Hello\r\n" )
);
IMPLEMENTATION SUPPORT
This module is supported by zuzu.pl, zuzu-rust, and zuzu-js on Node and Electron. It is not supported by zuzu-js in the browser.
DESCRIPTION
This runtime-supported module provides a deliberately low-level mail delivery API. It works with an explicit envelope sender, explicit envelope recipients, ordered message headers, and a raw BinaryString body.
It does not construct MIME messages, encode display names, generate a Message-ID, derive recipients from To, Cc, or Bcc headers, or add attachments. Higher-level composition modules should build the headers and body, then call this module.
EXPORTS
Classes
MailerConfigured sender class.
Mailer.capabilities()Parameters: none. Returns:
Dict. Reports backend delivery, TLS, authentication, and async support.Mailer({ transport?: String, host?: String, port?: Number, ... })Constructs a sender from named options. Returns:
Mailer.mailer.send(envelope_from, envelope_to, headers, body, options := {})Parameters:
envelope_fromis the sender address,envelope_tois a string or array of recipient addresses,headersis aPairList,bodyis aBinaryString, andoptionscontrols sending. Returns:MailResult. Sends one message.mailer.send_async(envelope_from, envelope_to, headers, body, options := {})Parameters: same as
send. Returns:Task. Asynchronously sends one message.
MailResultResult object returned by successful deliveries.
result.transport()Parameters: none. Returns:
String. Returns the delivery transport.result.accepted()Parameters: none. Returns:
Array. Returns accepted envelope recipients.result.rejected()Parameters: none. Returns:
Array. Returns rejected envelope recipients.result.message_id()Parameters: none. Returns:
Stringornull. Returns the suppliedMessage-IDheader value when present.result.response()Parameters: none. Returns:
Stringornull. Returns the backend delivery response text.result.to_Dict()Parameters: none. Returns:
Dict. Converts the result to a dictionary.
The module does not export a module-level capabilities() function. Use Mailer.capabilities().
CAPABILITIES
Mailer.capabilities() returns a Dict with stable keys:
{
smtp: true,
sendmail: true,
tls: true,
starttls: true,
auth: [ "plain", "login", "xoauth2" ],
async: true,
}
Backends report false or an empty array for features they cannot honestly provide. Browser hosts are importable but report no real delivery support.
MAILER OPTIONS
Create a sender with named options:
let mailer := new Mailer(
transport: "sendmail",
sendmail_path: "/usr/sbin/sendmail"
);
Supported options include:
transport"smtp"or"sendmail". Defaults to"smtp".host,port,timeoutSMTP host, port, and command timeout. Defaults are
localhost,25, and30seconds.submissionUses submission-style defaults: port
587and STARTTLS requested. Backends without STARTTLS support will reject sending clearly.tls,starttls,tls_verify,tls_server_nameTLS policy fields.
tls_verifydefaults to true.username,password,authAuthentication fields.
authmay beplain,login, orxoauth2. Authentication on a plaintext connection requires explicitallow_insecure_auth: true.smtputf8Permit non-ASCII envelope addresses only when the backend and server can honour SMTPUTF8.
reject_partialFor SMTP, throw if any recipient is rejected. The default returns a
MailResultwhen at least one recipient is accepted.sendmail_path,sendmail_argsSendmail-compatible binary path and extra fixed argument-vector items. The backend invokes:
sendmail_path sendmail_args... -i -f ENVELOPE_FROM RECIPIENT...No shell interpolation is used.
SENDING
mailer.send(envelope_from, envelope_to, headers, body, options := {})
mailer.send_async(envelope_from, envelope_to, headers, body, options := {})
envelope_to may be a single string or an array of strings. These are the only delivery recipients. Header fields are never used as envelope recipients.
headers must be a PairList, preserving order and duplicate fields. Dict headers are rejected. Header names must be strict RFC 5322 field name tokens with no colon or control characters. Header values must be String or BinaryString values and must not contain CR or LF.
body must be a BinaryString. Passing a String throws a clear type error so callers do not accidentally depend on host text encoding.
Serialization is:
- 1.
Headers in
PairListorder using CRLF line endings. - 2.
One blank CRLF separator.
- 3.
The body bytes exactly as supplied.
SMTP dot-stuffing is a wire encoding detail and does not mutate caller bytes.
MAIL RESULT
A successful send returns a MailResult with public fields:
{
transport: "smtp",
accepted: [ "recipient@example.test" ],
rejected: [],
message_id: "<example-1@example.test>",
response: "250 queued",
}
message_id is copied from a supplied Message-ID header when one is present. This module never generates one automatically.
COPYRIGHT AND LICENCE
std/net/smtp is copyright Toby Inkster.
It is free software; you may redistribute it and/or modify it under the terms of either the Artistic License 1.0 or the GNU General Public License version 2.