The Mail Filter (milter) Protocol
draft-adams-milter-protocol-00
This document is an Internet-Draft (I-D).
Anyone may submit an I-D to the IETF.
This I-D is not endorsed by the IETF and has no formal standing in the
IETF standards process.
| Document | Type | Active Internet-Draft (individual) | |
|---|---|---|---|
| Authors | J. Trent Adams , Murray Kucherawy | ||
| Last updated | 2026-10-26 | ||
| RFC stream | Independent Submission | ||
| Intended RFC status | Informational | ||
| Formats | |||
| Stream | ISE state | Submission Received | |
| Consensus boilerplate | Unknown | ||
| Document shepherd | (None) | ||
| IESG | IESG state | I-D Exists | |
| Telechat date | (None) | ||
| Responsible AD | (None) | ||
| Send notices to | (None) |
draft-adams-milter-protocol-00
TBD T. Adams
Internet-Draft Proofpoint, Inc.
Intended status: Informational M. Kucherawy, Ed.
Expires: 29 April 2027 26 October 2026
The Mail Filter (milter) Protocol
draft-adams-milter-protocol-00
Abstract
This document specifies the "milter" protocol, a binary request/
response protocol by which a Mail Transfer Agent (MTA) can delegate
inspection and modification of an SMTP transaction to one or more
external filtering processes.
Editorial Note
This note is to be removed before publishing as an RFC.
This document describes existing widely deployed practice originating
in the sendmail "libmilter" implementation. Prose sections marked
[[TODO]] are placeholders.
Publication is being sought to archive the protocol which has never
been publicly documented other than in its code form. The protocol
has not evolved substantially since the release of version 6, and
prior versions are considered historical.
Status of This Memo
This Internet-Draft is submitted in full conformance with the
provisions of BCP 78 and BCP 79.
Internet-Drafts are working documents of the Internet Engineering
Task Force (IETF). Note that other groups may also distribute
working documents as Internet-Drafts. The list of current Internet-
Drafts is at https://datatracker.ietf.org/drafts/current/.
Internet-Drafts are draft documents valid for a maximum of six months
and may be updated, replaced, or obsoleted by other documents at any
time. It is inappropriate to use Internet-Drafts as reference
material or to cite them other than as "work in progress."
This Internet-Draft will expire on 29 April 2027.
Adams & Kucherawy Expires 29 April 2027 [Page 1]
Internet-Draft Milter Protocol October 2026
Copyright Notice
Copyright (c) 2026 IETF Trust and the persons identified as the
document authors. All rights reserved.
This document is subject to BCP 78 and the IETF Trust's Legal
Provisions Relating to IETF Documents (https://trustee.ietf.org/
license-info) in effect on the date of publication of this document.
Please review these documents carefully, as they describe your rights
and restrictions with respect to this document. Code Components
extracted from this document must include Revised BSD License text as
described in Section 4.e of the Trust Legal Provisions and are
provided without warranty as described in the Revised BSD License.
Table of Contents
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 2
2. Conventions and Terminology . . . . . . . . . . . . . . . . . 3
3. Protocol Model . . . . . . . . . . . . . . . . . . . . . . . 3
4. Packet Framing . . . . . . . . . . . . . . . . . . . . . . . 4
5. Option Negotiation . . . . . . . . . . . . . . . . . . . . . 5
6. Commands (MTA to Filter) . . . . . . . . . . . . . . . . . . 8
7. Responses (Filter to MTA) . . . . . . . . . . . . . . . . . . 12
8. Macros . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
9. Error Handling and Timeouts . . . . . . . . . . . . . . . . . 18
10. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 19
11. Security Considerations . . . . . . . . . . . . . . . . . . . 19
12. References . . . . . . . . . . . . . . . . . . . . . . . . . 19
12.1. Normative References . . . . . . . . . . . . . . . . . . 19
12.2. Informative References . . . . . . . . . . . . . . . . . 20
Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . 20
Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 20
1. Introduction
Milter (a portmanteau of "mail filter") was officially introduced
into open source Sendmail 8.12.0 released on September 8, 2001. It
provided a plugin architecture by which a Mail Transfer Agent (MTA)
can communicate with an arbitrary number of local filtering agents to
observe and possibly modify messages in transit or influence their
delivery. Filters implementing the milter protocol (called
"milters") are optionally involved at each phase of an SMTP [RFC5321]
transaction.
Milter is also supported by Postfix, which together with Sendmail
provides milter capabilities to the bulk of open source MTA
deployment worldwide.
Adams & Kucherawy Expires 29 April 2027 [Page 2]
Internet-Draft Milter Protocol October 2026
2. Conventions and Terminology
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
document are to be interpreted as described in BCP 14 [RFC2119]
[RFC8174] when, and only when, they appear in all capitals, as shown
here.
MTA: The Mail Transfer Agent; the client of this protocol.
Filter (or milter): The server of this protocol.
Octet: An 8-bit byte.
Network byte order: Big-endian, most significant octet first.
Null-terminated string: A sequence of zero or more non-NUL octets
followed by one octet of value 0x00. Unless stated otherwise,
such strings are US-ASCII.
Numeric constants are given in hexadecimal with a "0x" prefix.
Command and response identifiers are single US-ASCII characters and
are shown in single quotes; the quotes are not part of the protocol.
3. Protocol Model
The milter protocol is a connection-oriented, binary, largely half-
duplex request/response protocol. The MTA connects to the filter and
drives the exchange; the filter reacts. There is no filter-initiated
request other than responses.
3.1. Transport
The protocol runs over any reliable, ordered, octet-stream transport.
In practice this is TCP [RFC9293] over IPv4 or IPv6, or a local
(AF_UNIX) stream socket. No port number is reserved; the port or
socket path is a matter of local configuration. The protocol
provides no authentication, integrity, or confidentiality of its own
(see Section 11).
3.2. Transaction Phases
One milter connection carries the negotiation phase followed by zero
or more SMTP connection contexts, each carrying zero or more message
transactions:
1. Option negotiation (Section 5), exactly once per milter
connection, before anything else.
Adams & Kucherawy Expires 29 April 2027 [Page 3]
Internet-Draft Milter Protocol October 2026
2. SMTP connection context: connection information, then HELO/EHLO.
3. Per-message transaction: envelope sender, envelope recipients,
DATA, headers, end of headers, body chunks, end of message.
4. End of message is the only point at which message modifications
may be requested.
An abort resets to the start of a message transaction while
preserving the SMTP connection context. A quit ends the milter
connection; a "quit but new connection follows" resets to the start
of an SMTP connection context while preserving negotiated options.
3.3. Normal Message Flow
MTA Filter
|--- 'O' OPTNEG ----------------------->|
|<-- 'O' OPTNEG (agreed) --------------|
|--- 'D' MACRO(for 'C') --------------->| (optional, no reply)
|--- 'C' CONNECT ---------------------->|
|<-- 'c' CONTINUE ---------------------|
|--- 'H' HELO ------------------------->|
|<-- 'c' CONTINUE ---------------------|
|--- 'M' MAIL ------------------------->|
|<-- 'c' CONTINUE ---------------------|
|--- 'R' RCPT ------------------------->| (once per recipient)
|<-- 'c' CONTINUE ---------------------|
|--- 'T' DATA ------------------------->|
|<-- 'c' CONTINUE ---------------------|
|--- 'L' HEADER ----------------------->| (once per header field)
|<-- 'c' CONTINUE ---------------------|
|--- 'N' EOH -------------------------->|
|<-- 'c' CONTINUE ---------------------|
|--- 'B' BODY ------------------------->| (repeated)
|<-- 'c' CONTINUE or 'S' SKIP -------|
|--- 'E' BODYEOB ---------------------->|
|<-- zero or more modification actions -|
|<-- final disposition ----------------|
|--- 'A' ABORT / 'Q' QUIT / 'K' QUIT_NC >|
4. Packet Framing
All protocol data units ("packets") share one framing:
Adams & Kucherawy Expires 29 April 2027 [Page 4]
Internet-Draft Milter Protocol October 2026
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| len (uint32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| cmd/resp | |
+-+-+-+-+-+-+-+-+ data (len - 1 octets) +
| ... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
len: Unsigned 32-bit integer in network byte order, giving the
number of octets that follow, i.e. one octet of command/response
identifier plus the length of the data. The value MUST be at
least 1. The length field itself is not counted.
cmd/resp: One octet identifying the command (Section 6) or response
(Section 7).
data: Exactly len-1 octets, whose interpretation depends on the
identifier. Where a field is a null-terminated string, the
terminating NUL is included in len.
A receiver MUST impose an upper bound on len and MUST close the
connection rather than attempt to buffer an implausibly large packet.
Implementations commonly bound the negotiated maximum body chunk
(Section 5.3) and reject packets exceeding it. A receiver MUST treat
an unknown identifier, a truncated packet, a missing NUL terminator,
or a data length inconsistent with the identifier's definition as a
protocol error and close the connection.
Multiple packets MAY be coalesced into a single transport write;
receivers MUST NOT rely on message boundaries in the transport
stream.
5. Option Negotiation
Immediately after the connection is established, the MTA MUST send
SMFIC_OPTNEG ('O') and the filter MUST reply with SMFIC_OPTNEG ('O').
No other command may precede this exchange.
'O' version (uint32) protocol version, 6 for this specification
actions (uint32) bitmask of SMFIF_* (Section 5.2)
protocol (uint32) bitmask of SMFIP_* (Section 5.3)
In the MTA's offer, "actions" and "protocol" advertise everything the
MTA is able to support. In the filter's reply, the filter MUST NOT
set any bit the MTA did not offer; the reply bits are the operative
agreement for the remainder of the connection. The filter MUST
Adams & Kucherawy Expires 29 April 2027 [Page 5]
Internet-Draft Milter Protocol October 2026
request in "actions" every modification it may later attempt, and
MUST set in "protocol" the bits describing the commands it wishes to
be spared and the replies it will omit. An MTA that receives a
version it does not support, or a bit it did not offer, MUST close
the connection.
The filter's reply MAY be followed by zero or more macro list
entries, permitted only if SMFIF_SETSYMLIST was negotiated:
stage (uint32) 0=connect 1=helo 2=mail 3=rcpt
4=data 5=eom 6=eoh
macros (string) space-separated macro names, NUL-terminated
Each entry replaces the MTA's default macro set for that stage. A
stage MUST NOT appear more than once.
5.1. Protocol Versions
Version 6 is specified by this document and is the only version
implementations are expected to support. Versions 2 and 4 exist in
historical deployments; they lack, among other things, the DATA and
UNKNOWN commands, recipient-parameter and sender-change actions, the
SKIP response, and the no-reply protocol bits. Implementations
SHOULD offer version 6 and MAY accept earlier versions for
interoperability.
5.2. Action Flags (SMFIF_*)
+============+===================+============================+
| Value | Name | Permits |
+============+===================+============================+
| 0x00000001 | SMFIF_ADDHDRS | Add header fields ('h') |
+------------+-------------------+----------------------------+
| 0x00000002 | SMFIF_CHGBODY | Replace the body ('b') |
+------------+-------------------+----------------------------+
| 0x00000004 | SMFIF_ADDRCPT | Add a recipient ('+') |
+------------+-------------------+----------------------------+
| 0x00000008 | SMFIF_DELRCPT | Delete a recipient ('-') |
+------------+-------------------+----------------------------+
| 0x00000010 | SMFIF_CHGHDRS | Change or delete header |
| | | fields ('m'), insert ('i') |
+------------+-------------------+----------------------------+
| 0x00000020 | SMFIF_QUARANTINE | Quarantine the message |
| | | ('q') |
+------------+-------------------+----------------------------+
| 0x00000040 | SMFIF_CHGFROM | Change the envelope sender |
| | | ('e') |
+------------+-------------------+----------------------------+
Adams & Kucherawy Expires 29 April 2027 [Page 6]
Internet-Draft Milter Protocol October 2026
| 0x00000080 | SMFIF_ADDRCPT_PAR | Add a recipient with ESMTP |
| | | parameters ('2') |
+------------+-------------------+----------------------------+
| 0x00000100 | SMFIF_SETSYMLIST | Send macro lists during |
| | | negotiation |
+------------+-------------------+----------------------------+
Table 1: Action Flags
5.3. Protocol Flags (SMFIP_*)
Bits in the first group suppress a command entirely: the MTA will not
send it and the filter will not reply to it. Bits in the second
group ("no reply") keep the command but declare that the filter will
send no response packet for it; the MTA MUST proceed as if
SMFIR_CONTINUE had been received. Filters MUST NOT send a response
for a stage whose no-reply bit was negotiated.
+============+===================+=========================+
| Value | Name | Meaning |
+============+===================+=========================+
| 0x00000001 | SMFIP_NOCONNECT | Do not send 'C' |
+------------+-------------------+-------------------------+
| 0x00000002 | SMFIP_NOHELO | Do not send 'H' |
+------------+-------------------+-------------------------+
| 0x00000004 | SMFIP_NOMAIL | Do not send 'M' |
+------------+-------------------+-------------------------+
| 0x00000008 | SMFIP_NORCPT | Do not send 'R' |
+------------+-------------------+-------------------------+
| 0x00000010 | SMFIP_NOBODY | Do not send 'B' |
+------------+-------------------+-------------------------+
| 0x00000020 | SMFIP_NOHDRS | Do not send 'L' |
+------------+-------------------+-------------------------+
| 0x00000040 | SMFIP_NOEOH | Do not send 'N' |
+------------+-------------------+-------------------------+
| 0x00000080 | SMFIP_NR_HDR | No reply for 'L' |
+------------+-------------------+-------------------------+
| 0x00000100 | SMFIP_NOUNKNOWN | Do not send 'U' |
+------------+-------------------+-------------------------+
| 0x00000200 | SMFIP_NODATA | Do not send 'T' |
+------------+-------------------+-------------------------+
| 0x00000400 | SMFIP_SKIP | Filter may send 'S' |
| | | (SKIP) |
+------------+-------------------+-------------------------+
| 0x00000800 | SMFIP_RCPT_REJ | Also report recipients |
| | | the MTA rejected |
+------------+-------------------+-------------------------+
| 0x00001000 | SMFIP_NR_CONN | No reply for 'C' |
Adams & Kucherawy Expires 29 April 2027 [Page 7]
Internet-Draft Milter Protocol October 2026
+------------+-------------------+-------------------------+
| 0x00002000 | SMFIP_NR_HELO | No reply for 'H' |
+------------+-------------------+-------------------------+
| 0x00004000 | SMFIP_NR_MAIL | No reply for 'M' |
+------------+-------------------+-------------------------+
| 0x00008000 | SMFIP_NR_RCPT | No reply for 'R' |
+------------+-------------------+-------------------------+
| 0x00010000 | SMFIP_NR_DATA | No reply for 'T' |
+------------+-------------------+-------------------------+
| 0x00020000 | SMFIP_NR_UNKN | No reply for 'U' |
+------------+-------------------+-------------------------+
| 0x00040000 | SMFIP_NR_EOH | No reply for 'N' |
+------------+-------------------+-------------------------+
| 0x00080000 | SMFIP_NR_BODY | No reply for 'B' |
+------------+-------------------+-------------------------+
| 0x00100000 | SMFIP_HDR_LEADSPC | Header values retain |
| | | leading space; no space |
| | | is added on output |
+------------+-------------------+-------------------------+
| 0x10000000 | SMFIP_MDS_256K | Maximum body chunk |
| | | 262144 octets |
+------------+-------------------+-------------------------+
| 0x20000000 | SMFIP_MDS_1M | Maximum body chunk |
| | | 1048576 octets |
+------------+-------------------+-------------------------+
Table 2: Protocol Flags
Absent an MDS bit, the maximum body chunk is 65535 octets. If both
MDS bits are offered the filter MUST select at most one. There is no
no-reply bit for end of message ('E'); a filter MUST always answer
'E'.
6. Commands (MTA to Filter)
Unless a no-reply or suppression bit was negotiated, the MTA MUST
wait for a response to each command before sending the next, and the
filter MUST send exactly one terminal response per command.
Adams & Kucherawy Expires 29 April 2027 [Page 8]
Internet-Draft Milter Protocol October 2026
+============+===============+================+
| Code | Name | Stage |
+============+===============+================+
| 'O' (0x4F) | SMFIC_OPTNEG | Negotiation |
+------------+---------------+----------------+
| 'D' (0x44) | SMFIC_MACRO | Any (no reply) |
+------------+---------------+----------------+
| 'C' (0x43) | SMFIC_CONNECT | Connection |
+------------+---------------+----------------+
| 'H' (0x48) | SMFIC_HELO | Connection |
+------------+---------------+----------------+
| 'M' (0x4D) | SMFIC_MAIL | Envelope |
+------------+---------------+----------------+
| 'R' (0x52) | SMFIC_RCPT | Envelope |
+------------+---------------+----------------+
| 'T' (0x54) | SMFIC_DATA | Envelope |
+------------+---------------+----------------+
| 'L' (0x4C) | SMFIC_HEADER | Message |
+------------+---------------+----------------+
| 'N' (0x4E) | SMFIC_EOH | Message |
+------------+---------------+----------------+
| 'B' (0x42) | SMFIC_BODY | Message |
+------------+---------------+----------------+
| 'E' (0x45) | SMFIC_BODYEOB | End of message |
+------------+---------------+----------------+
| 'U' (0x55) | SMFIC_UNKNOWN | Any |
+------------+---------------+----------------+
| 'A' (0x41) | SMFIC_ABORT | Any (no reply) |
+------------+---------------+----------------+
| 'Q' (0x51) | SMFIC_QUIT | Any (no reply) |
+------------+---------------+----------------+
| 'K' (0x4B) | SMFIC_QUIT_NC | Any (no reply) |
+------------+---------------+----------------+
Table 3: Command Codes
6.1. SMFIC_MACRO ('D')
'D' cmdcode (char) command letter these macros apply to
pairs ... name NUL value NUL, repeated to end of packet
Conveys named symbols ("macros") describing the state of the SMTP
session. It is not a command in its own right: it carries no reply,
and it MUST immediately precede the command identified by cmdcode.
Macro values persist for the scope of the stage in which they were
sent and are discarded when that scope ends. Names are conveyed
without the leading '$' or enclosing braces used in MTA configuration
syntax. See Section 8.
Adams & Kucherawy Expires 29 April 2027 [Page 9]
Internet-Draft Milter Protocol October 2026
6.2. SMFIC_CONNECT ('C')
'C' hostname (string) validated client name, or bracketed address
family (char) 'U' unknown, 'L' unix, '4' inet, '6' inet6
port (uint16) client source port, present unless family 'U'
address (string) textual address, present unless family 'U'
Sent once per SMTP connection, before any other transaction command.
When family is 'U', port and address are absent. For 'L', port is
present but meaningless and address is the socket path. Address
literals follow [RFC5321] textual form.
6.3. SMFIC_HELO ('H')
'H' helo (string) argument of the HELO or EHLO command
May occur more than once per SMTP connection. A second HELO/EHLO
resets the SMTP transaction but not the milter connection context.
6.4. SMFIC_MAIL ('M')
'M' args ... one or more NUL-terminated strings
The first string is the envelope sender in angle-bracketed [RFC5321]
form; the remainder, if any, are the ESMTP parameters of the MAIL
command, one per string. This command begins a message transaction.
6.5. SMFIC_RCPT ('R')
'R' args ... one or more NUL-terminated strings
As for 'M', but the first string is one envelope recipient. Sent
once per recipient. A rejection response applies only to that
recipient and does not terminate the transaction. If SMFIP_RCPT_REJ
was negotiated, recipients the MTA itself rejected are also reported,
distinguishable through macros.
6.6. SMFIC_DATA ('T')
'T' (no data)
Signals the SMTP DATA command, after the last recipient and before
any header. A rejection here rejects the whole message.
6.7. SMFIC_HEADER ('L')
'L' name (string) header field name, without the colon
value (string) header field value
Adams & Kucherawy Expires 29 April 2027 [Page 10]
Internet-Draft Milter Protocol October 2026
Sent once per header field, in the order the fields appear. Folded
fields are delivered with their embedded CRLF sequences intact and
are not unfolded. Unless SMFIP_HDR_LEADSPC was negotiated, the
whitespace separating the colon from the value is removed from value,
and the MTA reinserts a single space when emitting header fields
supplied by the filter.
6.8. SMFIC_EOH ('N')
'N' (no data)
Marks the end of the header block.
6.9. SMFIC_BODY ('B')
'B' chunk ... opaque body octets, not NUL-terminated
Sent zero or more times. Each chunk carries at most the negotiated
maximum (Section 5.3) minus framing overhead. Chunk boundaries are
arbitrary and carry no semantics: they need not align with line
boundaries, and a filter MUST NOT assume otherwise. Line endings are
CRLF as received on the wire. Dot-stuffing as defined in [RFC5321]
is removed by the MTA before the body is presented.
6.10. SMFIC_BODYEOB ('E')
'E' (no data)
Marks the end of the message body. This is the only stage at which
the filter may send modification actions (Section 7.5). The filter
MUST conclude with exactly one terminal response.
6.11. SMFIC_UNKNOWN ('U')
'U' command (string) the unrecognized SMTP command text
Reports an SMTP command the MTA did not recognize or could not
process. It does not change the transaction state.
6.12. SMFIC_ABORT ('A')
'A' (no data)
Abandons the current message transaction. The filter MUST NOT reply
and MUST discard all state accumulated since 'M', retaining
connection and HELO state. It may arrive at any point in a
transaction, including after 'E'.
Adams & Kucherawy Expires 29 April 2027 [Page 11]
Internet-Draft Milter Protocol October 2026
6.13. SMFIC_QUIT ('Q') and SMFIC_QUIT_NC ('K')
'Q' (no data) close the milter connection
'K' (no data) close the SMTP connection context; reuse this one
Neither is answered. After 'Q' the filter MUST release all state and
close the connection. After 'K' the filter MUST discard transaction
and connection state but retain the negotiated options and await a
new 'C' on the same milter connection.
7. Responses (Filter to MTA)
Responses fall into three classes: terminal dispositions, which
conclude the handling of a command; non-terminal responses, which do
not conclude it; and modification actions, valid only at end of
message and always followed by a terminal disposition.
Adams & Kucherawy Expires 29 April 2027 [Page 12]
Internet-Draft Milter Protocol October 2026
+============+===================+======================+
| Code | Name | Class |
+============+===================+======================+
| 'c' (0x63) | SMFIR_CONTINUE | Terminal |
+------------+-------------------+----------------------+
| 'a' (0x61) | SMFIR_ACCEPT | Terminal |
+------------+-------------------+----------------------+
| 'r' (0x72) | SMFIR_REJECT | Terminal |
+------------+-------------------+----------------------+
| 'd' (0x64) | SMFIR_DISCARD | Terminal |
+------------+-------------------+----------------------+
| 't' (0x74) | SMFIR_TEMPFAIL | Terminal |
+------------+-------------------+----------------------+
| 'y' (0x79) | SMFIR_REPLYCODE | Terminal |
+------------+-------------------+----------------------+
| 'f' (0x66) | SMFIR_SHUTDOWN | Terminal |
+------------+-------------------+----------------------+
| 'p' (0x70) | SMFIR_PROGRESS | Non-terminal |
+------------+-------------------+----------------------+
| 'S' (0x53) | SMFIR_SKIP | Terminal (body only) |
+------------+-------------------+----------------------+
| 'O' (0x4F) | SMFIC_OPTNEG | Negotiation only |
+------------+-------------------+----------------------+
| '+' (0x2B) | SMFIR_ADDRCPT | Modification |
+------------+-------------------+----------------------+
| '2' (0x32) | SMFIR_ADDRCPT_PAR | Modification |
+------------+-------------------+----------------------+
| '-' (0x2D) | SMFIR_DELRCPT | Modification |
+------------+-------------------+----------------------+
| 'e' (0x65) | SMFIR_CHGFROM | Modification |
+------------+-------------------+----------------------+
| 'h' (0x68) | SMFIR_ADDHEADER | Modification |
+------------+-------------------+----------------------+
| 'i' (0x69) | SMFIR_INSHEADER | Modification |
+------------+-------------------+----------------------+
| 'm' (0x6D) | SMFIR_CHGHEADER | Modification |
+------------+-------------------+----------------------+
| 'b' (0x62) | SMFIR_REPLBODY | Modification |
+------------+-------------------+----------------------+
| 'q' (0x71) | SMFIR_QUARANTINE | Modification |
+------------+-------------------+----------------------+
Table 4: Response Codes
7.1. Terminal Dispositions
SMFIR_CONTINUE ('c'), no data: Proceed with normal processing. This
Adams & Kucherawy Expires 29 April 2027 [Page 13]
Internet-Draft Milter Protocol October 2026
is the implied response whenever a no-reply protocol bit is in
effect.
SMFIR_ACCEPT ('a'), no data: Accept without further filtering by
this filter. Sent at a recipient stage it accepts that recipient;
sent at any other stage it accepts the message and this filter is
not consulted again for the remainder of the transaction.
SMFIR_REJECT ('r'), no data: Reject permanently. The MTA issues a
5yz reply. At a recipient stage only that recipient is rejected;
elsewhere the message is rejected.
SMFIR_TEMPFAIL ('t'), no data: Reject temporarily. The MTA issues a
4yz reply, inviting a later retry. Scope is as for SMFIR_REJECT.
SMFIR_DISCARD ('d'), no data: Accept the message at the SMTP level
and then silently discard it. The sending client is given a
success reply. If sent at a recipient stage, that recipient's
copy is discarded.
SMFIR_SHUTDOWN ('f'), no data: Reject and close the SMTP connection
immediately. Not supported by all MTAs; filters SHOULD NOT depend
on it.
The effect of a disposition sent before the message transaction
begins — that is, at connect or HELO — applies to the SMTP connection
rather than to a single message.
7.2. SMFIR_REPLYCODE ('y')
'y' reply (string) "NNN[ ENH.S.C] text", NUL-terminated
Rejects with a filter-supplied SMTP reply. The first three octets
MUST be a three-digit reply code beginning with '4' or '5' as defined
in [RFC5321], optionally followed by a space, an enhanced status code
[RFC3463], and free text. Whether the reply is treated as temporary
or permanent follows its leading digit. The text MUST NOT contain
bare CR or LF; a multiline reply is expressed by embedding CRLF-
separated lines formatted per [RFC5321], and MTAs MAY refuse such
replies. A "%" in the text is interpreted by some MTAs as
introducing a format directive and MUST therefore be escaped as "%%".
7.3. SMFIR_PROGRESS ('p')
'p' (no data)
Adams & Kucherawy Expires 29 April 2027 [Page 14]
Internet-Draft Milter Protocol October 2026
Indicates that the filter is still working and requests that the MTA
reset its response timer. It does not conclude the command; the
filter MUST still send a terminal response. It MAY be sent
repeatedly and is intended chiefly for long-running end-of-message
processing.
7.4. SMFIR_SKIP ('S')
'S' (no data)
Valid only in response to SMFIC_BODY and only if SMFIP_SKIP was
negotiated. The filter has seen as much of the body as it needs; the
MTA MUST stop sending 'B' packets for this message and proceed to
'E'. It is equivalent to SMFIR_CONTINUE with respect to disposition.
7.5. Modification Actions
Modification actions MUST be sent only in response to SMFIC_BODYEOB,
MUST be permitted by the action flags agreed during negotiation, and
MUST be followed by exactly one terminal disposition. Any number may
be sent, and their effects are applied by the MTA in the order
received. A filter MUST NOT expect the MTA to report the outcome of
an individual action; the MTA MAY reject the whole connection if an
action is malformed or unnegotiated.
Adams & Kucherawy Expires 29 April 2027 [Page 15]
Internet-Draft Milter Protocol October 2026
'h' name (string) append a header field
value (string)
---
'i' index (uint32) insert a header field; 1 = before the first
name (string) existing field, 0 is treated as 1; an index
value (string) past the end appends
---
'm' index (uint32) 1-based occurrence of this field name to
name (string) change; empty value deletes the field
value (string)
---
'b' data ... replacement body octets, not NUL-terminated
---
'+' rcpt (string) add envelope recipient
---
'2' rcpt (string) add envelope recipient with ESMTP parameters
args (string)
---
'-' rcpt (string) delete envelope recipient
---
'e' from (string) replace envelope sender
args (string) optional ESMTP parameters; may be absent
---
'q' reason (string) quarantine; empty reason releases
Notes on individual actions:
* Header names and values in 'h', 'i', and 'm' are subject to the
SMFIP_HDR_LEADSPC convention described in Section 6. Values MUST
NOT contain bare CR or LF; folding is expressed with CRLF followed
by whitespace.
* 'm' with an index greater than the number of occurrences of that
field name has no effect. Deletion renumbers subsequent
occurrences, so a filter deleting several occurrences SHOULD work
from the highest index downward.
* 'b' replaces the entire body. It MAY be sent repeatedly, in which
case the chunks are concatenated in order to form the new body;
sending 'b' with no data yields an empty body. Each packet is
bounded as for SMFIC_BODY. Lines MUST be CRLF-terminated and MUST
NOT be dot-stuffed.
* Recipient and sender addresses are in angle-bracketed [RFC5321]
form. Adding a recipient that is already present, or deleting one
that is not, has no effect.
Adams & Kucherawy Expires 29 April 2027 [Page 16]
Internet-Draft Milter Protocol October 2026
* 'q' places the message in the MTA's held queue rather than
delivering it; the reason is recorded for the administrator. It
is normally paired with a terminal SMFIR_ACCEPT.
8. Macros
Macros are name/value pairs supplied through SMFIC_MACRO (Section 6)
and give the filter access to MTA state not otherwise carried on the
wire. Availability is MTA-specific and, when SMFIF_SETSYMLIST is
negotiated, configurable per stage. A filter MUST tolerate the
absence of any macro. The following are widely implemented.
+===========================+==========+=========================+
| Name | Earliest | Value |
| | stage | |
+===========================+==========+=========================+
| j | connect | Canonical name of the |
| | | MTA host |
+---------------------------+----------+-------------------------+
| _ | connect | Validated client name |
| | | and address |
+---------------------------+----------+-------------------------+
| {daemon_name} | connect | Name of the MTA daemon |
| | | instance |
+---------------------------+----------+-------------------------+
| {daemon_port} | connect | Local port the client |
| | | connected to |
+---------------------------+----------+-------------------------+
| {if_name}, {if_addr} | connect | Local interface name |
| | | and address |
+---------------------------+----------+-------------------------+
| {client_addr}, | connect | Client address and |
| {client_port} | | source port |
+---------------------------+----------+-------------------------+
| {client_name} | connect | Client PTR name, if |
| | | verified |
+---------------------------+----------+-------------------------+
| {client_ptr} | connect | Result of the reverse |
| | | lookup |
+---------------------------+----------+-------------------------+
| {client_connections} | connect | Concurrent connections |
| | | from this client |
+---------------------------+----------+-------------------------+
| {tls_version}, {cipher}, | helo | TLS session parameters |
| {cipher_bits} | | |
+---------------------------+----------+-------------------------+
| {cert_subject}, | helo | Client certificate |
| {cert_issuer} | | identity |
Adams & Kucherawy Expires 29 April 2027 [Page 17]
Internet-Draft Milter Protocol October 2026
+---------------------------+----------+-------------------------+
| {verify} | helo | Certificate |
| | | verification result |
+---------------------------+----------+-------------------------+
| {auth_type}, | mail | SASL mechanism and |
| {auth_authen} | | authenticated identity |
+---------------------------+----------+-------------------------+
| {auth_author} | mail | Authorization identity, |
| | | if asserted |
+---------------------------+----------+-------------------------+
| {auth_ssf} | mail | SASL security strength |
| | | factor |
+---------------------------+----------+-------------------------+
| {mail_addr}, {mail_host}, | mail | Resolved envelope |
| {mail_mailer} | | sender |
+---------------------------+----------+-------------------------+
| i | mail | MTA queue identifier |
| | | for this message |
+---------------------------+----------+-------------------------+
| {rcpt_addr}, {rcpt_host}, | rcpt | Resolved current |
| {rcpt_mailer} | | recipient |
+---------------------------+----------+-------------------------+
| {rcpt_reject} | rcpt | Set when the MTA itself |
| | | rejected this recipient |
+---------------------------+----------+-------------------------+
Table 5: Commonly Available Macros
9. Error Handling and Timeouts
The protocol carries no error response. Any framing violation,
unexpected or out-of-sequence identifier, or action that was not
negotiated is a protocol error, and the detecting party MUST close
the connection without further exchange.
An MTA MUST apply a timeout to each response and SHOULD apply
separate timeouts to connection establishment, to sending, and to
end-of-message processing. SMFIR_PROGRESS restarts the response
timer. On timeout, or on any failure to connect to or communicate
with a filter, the MTA MUST apply a locally configured default
action; a temporary rejection is RECOMMENDED as it is fail-closed
without permanently losing mail.
Where an MTA consults several filters, it does so in a configured
order, passing each stage through the filters in turn; the first non-
continue disposition terminates consideration of that stage, and
modifications made by one filter are visible to those following it.
Adams & Kucherawy Expires 29 April 2027 [Page 18]
Internet-Draft Milter Protocol October 2026
10. IANA Considerations
This document specifies no actions for IANA.
11. Security Considerations
The protocol provides no authentication, integrity protection, or
confidentiality. A milter connection can carry the full content of
every message, including credentials asserted through macros, in
cleartext, and a filter can reject, discard, or rewrite any message.
Deployments MUST therefore confine milter traffic to a trusted path —
a local socket with restrictive permissions, a loopback interface, or
a channel protected by TLS [RFC8446] or an equivalent — and MTAs MUST
NOT accept filter connections from, nor connect to filters at,
unauthenticated network locations.
Further considerations: length fields are attacker-influenced and
invite memory exhaustion if not bounded; a slow or wedged filter is a
denial-of-service vector against the MTA, and the fail-open default
action is a filtering-bypass vector; header and body modifications
can invalidate signatures such as DKIM [RFC6376]; filter-supplied
reply text is echoed to untrusted clients and can leak internal
detail or be used for injection if not sanitized.
12. References
12.1. Normative References
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119,
DOI 10.17487/RFC2119, March 1997,
<https://www.rfc-editor.org/info/rfc2119>.
[RFC3463] Vaudreuil, G., "Enhanced Mail System Status Codes",
RFC 3463, DOI 10.17487/RFC3463, January 2003,
<https://www.rfc-editor.org/info/rfc3463>.
[RFC5321] Klensin, J., "Simple Mail Transfer Protocol", RFC 5321,
DOI 10.17487/RFC5321, October 2008,
<https://www.rfc-editor.org/info/rfc5321>.
[RFC5322] Resnick, P., Ed., "Internet Message Format", RFC 5322,
DOI 10.17487/RFC5322, October 2008,
<https://www.rfc-editor.org/info/rfc5322>.
[RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC
2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174,
May 2017, <https://www.rfc-editor.org/info/rfc8174>.
Adams & Kucherawy Expires 29 April 2027 [Page 19]
Internet-Draft Milter Protocol October 2026
12.2. Informative References
[RFC6376] Crocker, D., Ed., Hansen, T., Ed., and M. Kucherawy, Ed.,
"DomainKeys Identified Mail (DKIM) Signatures", STD 76,
RFC 6376, DOI 10.17487/RFC6376, September 2011,
<https://www.rfc-editor.org/info/rfc6376>.
[RFC8446] Rescorla, E., "The Transport Layer Security (TLS) Protocol
Version 1.3", RFC 8446, DOI 10.17487/RFC8446, August 2018,
<https://www.rfc-editor.org/info/rfc8446>.
[RFC9293] Eddy, W., Ed., "Transmission Control Protocol (TCP)",
STD 7, RFC 9293, DOI 10.17487/RFC9293, August 2022,
<https://www.rfc-editor.org/info/rfc9293>.
Acknowledgments
[[TODO]]
Authors' Addresses
Trent Adams
Proofpoint, Inc.
Email: tadams@proofpoint.com
Murray Kucherawy (editor)
Email: superuser@gmail.com
Adams & Kucherawy Expires 29 April 2027 [Page 20]