Builds Received: trace header fields (RFC 5321 §4.4).
Received: from client.example.net ([192.0.2.7])
by mx.example.com with ESMTP id 0Q7c3XbK2mA9fZ
for <user@example.com>; Sun, 4 Oct 2026 12:00:00 +0000The with value is an RFC 3848 transmission type, see protocol/1.
Values are inserted as given, so they must already be validated: the
EHLO name as a domain or address literal, the recipient as a mailbox.
Summary
Functions
Formats an IP address as an RFC 5321 address literal.
Returns the complete header field, ending in CRLF.
Returns the RFC 3848 transmission type for a session.
Types
@type fields() :: %{ :helo => String.t(), :remote_ip => :inet.ip_address(), :by => String.t(), :protocol => String.t(), optional(:id) => String.t() | nil, optional(:for) => String.t() | nil, optional(:date) => DateTime.t(), optional(:tls) => String.t() | nil }
Functions
@spec address_literal(:inet.ip_address()) :: String.t()
Formats an IP address as an RFC 5321 address literal.
iex> Sovite.Message.Received.address_literal({192, 0, 2, 7})
"[192.0.2.7]"
iex> Sovite.Message.Received.address_literal({8193, 3512, 0, 0, 0, 0, 0, 1})
"[IPv6:2001:db8::1]"
Returns the complete header field, ending in CRLF.
:for is the recipient to show. Leave it out for messages with several
recipients, so they are not disclosed to each other. :date defaults to
now. :tls describes the encryption, as Sovite.TLS.describe/1 does,
and is shown in a comment like Postfix does:
Received: from client.example.net ([192.0.2.7])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits))
by mx.example.com with ESMTPS id 0Q7c3XbK2mA9fZ; ...
Returns the RFC 3848 transmission type for a session.
iex> Sovite.Message.Received.protocol(esmtp: true, tls: true)
"ESMTPS"
iex> Sovite.Message.Received.protocol(esmtp: false)
"SMTP"
iex> Sovite.Message.Received.protocol(lmtp: true, auth: true)
"LMTPA"