Coffey LabsDWG CL-01
Get in touch
Drawing list

Sheet index

No.SheetContents
A · Company
A-00CoverBuilt to be run, not rented.
A-01ProductsOur software and services, and the smaller tools
A-02CompanyWhere we came from, the founder
A-03NewsCompany announcements
A-04PressDescriptions, facts, brand kit
A-05How we workThe four rules, and the runs behind them
A-06LicensingCopyleft by default, every license
A-07SponsorWhat sponsorship pays for
A-08ContactIssues first, then the addresses
P · Products
P-01inbuxaMail server, console and webmail
P-02ihasmailImmutable webmail for Stalwart
P-03ihasvpnWireGuard server with a web console
P-04Cairn OBSKubernetes-native log aggregation
P-05HotDog CMSOpen source website builder
S · Services
S-01LINUXexpertCertification study guides and practice exams
X · Elsewhere
X-01Forum ↗community.coffeylabs.org
X-02Source code ↗git.coffeylabs.org
X-03GitHub mirror ↗github.com/Coffey-Labs
X-04Discord ↗The hangout
X-05Swag ↗Shirts, hats, mugs and stickers
L · Legal
L-01PrivacyWhat we collect, and your rights
L-02Terms of useThe rules for this site
L-03AI disclosureWhere AI is and isn’t used
↑↓ moveEnter openEsc close
Specification

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.

About this specification
Version1
Date2026-11-03
StatusStable. Registration of its media type and report type with IANA requested on 2026-11-03, under review.
Change controllerCoffey Labs LLC
Contactspecs@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:

  1. A summary for people, text/plain. Its wording isn't specified, and programs MUST NOT parse it.
  2. The envelope for programs, of type application/vnd.coffeylabs.journal-report (section 3).
  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.

Fields of the envelope part
FieldValue
VersionRequired, and first. The version of this specification, 1.
Reporting-MTARequired. The server that wrote the report, as dns; and its name.
Queue-IDRequired. The writer's identifier for the message in its queue. It has no meaning to anyone else.
Arrival-DateRequired. When the server queued the message, as an RFC 5322 date.
DirectionRequired. outgoing, incoming or internal (section 3.1).
AuthenticatedRequired. yes if the sender signed in to this server, otherwise no.
HeldRequired. 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-FromRequired, once. The envelope sender in angle brackets. <> is the empty sender a bounce has.
Original-Rcpt-ToRequired, 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. rule holds the rule's name.
  • to, cc: the address is in the original's To or Cc header.
  • list: the recipient was reached through another address, such as a list's, and via holds it. It comes from the DSN ORCPT parameter (RFC 3461). A writer MUST leave out an ORCPT that 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 called bcc: 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-type and 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 an addressed value it doesn't know as saying nothing.
  • A reader MUST NOT treat a report with a higher Version as 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-Encoding that fits: binary for a part with a NUL or a line past 998 bytes, 8bit for one with non-ASCII bytes, otherwise 7bit.
  • Over SMTP, a report that holds 8bit MUST be sent with BODY=8BITMIME (RFC 6152), and one that holds binary with BODY=BINARYMIME and BDAT (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 ORCPT behind via are 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.