The journal report format
A message that carries a copy of another message, untouched, with the SMTP envelope it really traveled with: the sender, and every recipient, including the ones its headers don't show. A mail server writes one, and an archive reads it.
| Version | 1 |
|---|---|
| Date | 2026-11-03 |
| Status | Stable. Registration of its media type and report type with IANA requested on 2026-11-03, under review. |
| Change controller | Coffey Labs LLC |
| Contact | specs@coffeylabs.org |
1. Why
A stored message doesn't say who got it. Blind copies leave no trace in its headers, the members of a list appear only as the list's address, and a server can add recipients by rule. The only full record is the SMTP envelope, and the envelope is gone once the message is delivered.
So a server that keeps a journal has to keep the envelope beside the message.
This specification fixes how: one report, in the multipart/report
form mail servers already use for bounces and feedback, so that an archive can
read reports from any server the same way.
It describes a format and says nothing about what any law or regulation requires, or whether a journal meets it.
The key words “MUST”, “MUST NOT”, “SHOULD”, “SHOULD NOT” and “MAY” are to be read as described in BCP 14 (RFC 2119 and RFC 8174) when, and only when, they appear in all capitals.
2. The report
A journal report is a message whose top-level type is
multipart/report (RFC 6522), with the
report-type parameter
vnd.coffeylabs.journal-report. It has exactly three parts, in this
order:
- A summary for people,
text/plain. Its wording isn't specified, and programs MUST NOT parse it. - The envelope for programs, of type
application/vnd.coffeylabs.journal-report(section 3). - The original message,
message/rfc822, byte for byte as the server queued it (section 5).
From: Journal <[email protected]>
Subject: Journal report: Q3 figures
MIME-Version: 1.0
Content-Type: multipart/report;
report-type="vnd.coffeylabs.journal-report"; boundary="b"
--b
Content-Type: text/plain; charset=utf-8
Sender: [email protected]
Not in To or Cc: [email protected]
--b
Content-Type: application/vnd.coffeylabs.journal-report
Version: 1
Reporting-MTA: dns; mx.example.com
Queue-ID: 1a2b3c
Arrival-Date: Mon, 28 Sep 2026 14:03:11 +0000
Direction: outgoing
Authenticated: yes
Held: no
Original-Mail-From: <[email protected]>
Original-Rcpt-To: <[email protected]>; addressed=to
Original-Rcpt-To: <[email protected]>; addressed=cc
Original-Rcpt-To: <[email protected]>; addressed=not-in-headers
Original-Rcpt-To: <[email protected]>; addressed=list; via=<[email protected]>
Original-Rcpt-To: <[email protected]>; addressed=rule; rule="Copy finance"
--b
Content-Type: message/rfc822
Content-Disposition: attachment; filename="original.eml"
From: [email protected]
To: [email protected]
...
--b--
The report's own headers aren't specified, apart from those MIME needs. A reader MUST NOT take anything about the original from them, and a writer MAY add others.
3. The envelope part
The part is UTF-8 text, one field a line, each line ending in CRLF. A field is its name, a colon, a space and its value. Fields are modeled on those of RFC 5965 where they mean the same thing, but unlike mail headers they are never folded, so each line can be read alone. A line MUST NOT pass 998 bytes.
| Field | Value |
|---|---|
Version | Required, and first. The version of this specification, 1. |
Reporting-MTA | Required. The server that wrote the report, as dns; and its name. |
Queue-ID | Required. The writer's identifier for the message in its queue. It has no meaning to anyone else. |
Arrival-Date | Required. When the server queued the message, as an RFC 5322 date. |
Direction | Required. outgoing, incoming or internal (section 3.1). |
Authenticated | Required. yes if the sender signed in to this server, otherwise no. |
Held | Required. yes if the server held the message for review when it was queued, otherwise no. A held message may never have been delivered. |
Original-Mail-From | Required, once. The envelope sender in angle brackets. <> is the empty sender a bounce has. |
Original-Rcpt-To | Required, once per envelope recipient (section 3.2). |
3.1 Direction
outgoing: from someone on this server to at least one recipient elsewhere. Mail with nobody on this server on either side, relayed through it, also counts as outgoing.incoming: from elsewhere to someone on this server.internal: from someone on this server to people on this server only.
3.2 Recipients
rcpt-field = "Original-Rcpt-To: <" Mailbox ">; addressed=" how CRLF
how = "to" / "cc" / "not-in-headers"
/ "list; via=<" Mailbox ">"
/ "rule; rule=" quoted-string
Mailbox is as in RFC 5321, extended by RFC 6531 where the address
isn't ASCII. A quoted-string is in double quotes, with
" and \ preceded by \. It may hold any
UTF-8 but no control characters.
addressed says what the message and envelope show about how this
recipient came to be there. A writer MUST use the first of these that applies:
rule: a rule on this server added the recipient or redirected the message to it.ruleholds the rule's name.to,cc: the address is in the original'sToorCcheader.list: the recipient was reached through another address, such as a list's, andviaholds it. It comes from the DSNORCPTparameter (RFC 3461). A writer MUST leave out anORCPTthat isn't plainly an address, since whoever sends the message can write anything there.not-in-headers: none of these. A blind copy looks like this. So does a list's post arriving for a subscriber, whose address its headers don't name, and a message delivered through an alias. This is why the value is not calledbcc: it doesn't show that the sender meant to hide anyone, and a reader MUST NOT present it as if it did.
The report lists the envelope this server saw. Recipients in the headers that another server handled aren't on it, and a recipient on an incoming message is only one of the people the sender wrote to.
4. Writers and readers
- A writer MUST write one report per message, per destination, with the whole envelope. A message to 40 recipients is one report.
- A writer MUST NOT journal its own journal reports, and SHOULD send them with the empty envelope sender, so that a refusal can't come back as mail.
- A reader MUST recognize a report by its
report-typeand read the envelope only from the second part. Subject, Message-ID and the rest come from the third part. - A reader MUST ignore fields it doesn't know, and parameters it doesn't know
after a recipient's
addressed. It MUST treat anaddressedvalue it doesn't know as saying nothing. - A reader MUST NOT treat a report with a higher
Versionas this version. Versions only rise for changes that a reader following these rules would misread.
5. Keeping the original whole
RFC 2046 lets message/rfc822 be only 7bit,
8bit or binary, so the third part can't be protected by
base64 or quoted-printable. That is the point of it: the bytes are the bytes. The
cost falls on delivery.
- The writer MUST label each part with the
Content-Transfer-Encodingthat fits:binaryfor a part with a NUL or a line past 998 bytes,8bitfor one with non-ASCII bytes, otherwise7bit. - Over SMTP, a report that holds
8bitMUST be sent withBODY=8BITMIME(RFC 6152), and one that holdsbinarywithBODY=BINARYMIMEandBDAT(RFC 3030). - A writer MUST NOT re-encode, wrap or otherwise change the original to get a report through. If the next server doesn't offer what the report needs, the writer MUST NOT send it there. It SHOULD keep the report and tell its administrator.
- A server after the next hop can still change a message. An archive SHOULD take reports directly.
6. Security considerations
- A report reveals what the message hid. It names recipients who were deliberately left out of the headers. Anyone who can read reports can read everything the mail says and who really got it, so they need the protection of the most sensitive mail on the server. A writer SHOULD send them only over TLS it has verified, or to an address on the same server.
- The sender writes much of what a report shows. The original's
headers and the
ORCPTbehindviaare the sender's claims. What this server itself knows is the envelope, the time, the direction and whether the sender signed in. - Values stay on their line. A writer MUST replace control characters in any value, so that nothing a sender controls can start a new field. A reader MUST treat each line as one field.
- A report proves nothing by itself. Nothing here signs it, and whoever holds one can edit it. A writer that wants changes to show has to record a hash somewhere else, or sign the report some other way.
7. The earlier layout
inbuxa from 2026.9.29 through 27.1.0-rc.7, and every 2026 release since, write a
multipart/mixed of a text/plain list of fields and a
message/rfc822 original. It isn't this format, and its list isn't
reliably parsable. A reader MAY accept it for the original alone. Archives will hold
some, since a stored report can't be rewritten without breaking any hash kept of it.
8. IANA registration
application/vnd.coffeylabs.journal-report is for the vendor tree of
the Media Types registry (RFC 6838):
- Required parameters: none
- Optional parameters: none
- Encoding considerations: 8bit; UTF-8 text with CRLF line endings
- Security considerations: section 6 of this page
- Interoperability considerations: none known
- Published specification: this page,
https://coffeylabs.org/specs/journal-report/ - Applications that use this media type: mail servers that keep journals, and archives that read them
- Intended usage: COMMON. Suitable for use as a report-type (the
second body part) of
multipart/report, RFC 6522. - Change controller: Coffey Labs LLC (specs@coffeylabs.org)
For the Report Type registry that RFC 8460 created:
- Report-Type:
vnd.coffeylabs.journal-report - Media Type:
application/vnd.coffeylabs.journal-report - Registered By: this page
9. Implementations
inbuxa-server (opens in a new tab) writes it from 27.1.0-rc.8, to its own journal and to outside archives. It is open source under AGPL-3.0.
Changes
- Version 1, 2026-11-03: first version.