The bounce service: tells senders about failed and delayed delivery, and about successful delivery when they ask for it (DSN, RFC 3461).
Notifications are built with Sovite.DSN and queued like any other
message, from the null sender (MAIL FROM:<>). The rules:
- Failed recipients are reported to the sender in one notification per delivery attempt.
- Delay warnings (
queue.delay_warning) are sent once per message. - The
NOTIFYparameter of each recipient decides which of these are sent for it; that is up to the caller. Success notifications (NOTIFY=SUCCESS) report recipients delivered to a mailbox, relayed to a server that does not support DSN, or expanded by an alias to several addresses. - Notifications carry the
ENVIDand each recipient'sORCPT. A failure notification for a message sent withRET=FULLreturns the whole message, unless it is larger thanbounce.size_limitor binary (BINARYMIME); otherwise, and for every other notification, only the header section. - Nothing is ever sent to the null sender (RFC 5321 §6.1, RFC 3834):
a failed notification is a double bounce. It is reported to
bounce.double_bounce_recipientwhen set, otherwise only logged. A failed double-bounce report is only logged, so notifications can never loop. - Notifications about a
REQUIRETLSmessage are sent withREQUIRETLStoo (RFC 8689 §4.3), and only include the message's header section, as ifRET=HDRS(RFC 8689 §5). - Notifications about internationalized mail (internationalized
addresses, or UTF-8 header fields in a message sent with
SMTPUTF8) are RFC 6533 ones, sent withSMTPUTF8, seeSovite.DSN.
Summary
Types
Options: :hostname, :directory (the spool), :max_lifetime
(milliseconds, for "will retry until"), :double_bounce_recipient
(or nil), and optionally :expand, a function that turns the
notification's recipient into the addresses to queue it for (aliases),
and :size_limit, the largest message returned whole (bytes, default
50000).
Where the original message is, as returned by Sovite.Queue.Spool.load/2,
possibly with more keys.
Functions
Reports recipients (address and Sovite.Queue.Record.details()
pairs) of the message in entry.
Types
@type opts() :: %{ :hostname => String.t(), :directory => Path.t(), :max_lifetime => pos_integer(), :double_bounce_recipient => String.t() | nil, optional(:expand) => (String.t() -> [String.t(), ...]), optional(:size_limit) => non_neg_integer() }
Options: :hostname, :directory (the spool), :max_lifetime
(milliseconds, for "will retry until"), :double_bounce_recipient
(or nil), and optionally :expand, a function that turns the
notification's recipient into the addresses to queue it for (aliases),
and :size_limit, the largest message returned whole (bytes, default
50000).
@type source() :: %{ :path => Path.t(), :message_offset => non_neg_integer(), :message_size => non_neg_integer(), :prefix => binary(), optional(atom()) => term() }
Where the original message is, as returned by Sovite.Queue.Spool.load/2,
possibly with more keys.
Functions
@spec notify( :failure | :delay | :success, Sovite.Queue.Entry.t(), source(), [{String.t(), map()}], opts() ) :: {:ok, String.t() | nil} | {:error, term()}
Reports recipients (address and Sovite.Queue.Record.details()
pairs) of the message in entry.
Returns {:ok, queue_id} for the queued notification, {:ok, nil} when
the rules say not to send one, or {:error, reason} if it could not be
queued; the caller should then try again later.