Skip to main content

The Mail Filter (milter) Protocol
draft-adams-milter-protocol-00

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]