Search by

phil / bounce-parser

phil

Messages received on a bounce mailbox read and classified: delivery status notifications (RFC 3464, RFC 6533), abuse feedback reports (RFC 5965) behind an authenticator, bounces written as text, automatic replies (RFC 3834), enhanced status codes (RFC 3463), VERP return paths, and ordered rules of t

0.1.0-alpha 2026-11-11 06:11 UTC

This package is auto-updated.

Last update: 2026-11-11 13:29:43 UTC


README

Know what every message on your bounce mailbox says, and what to do about the address it names.

phil/bounce-parser reads a message received on a bounce mailbox and says what it is: a delivery status notification (RFC 3464, and RFC 6533 for international addresses), an abuse feedback report (RFC 5965), a bounce written as text by a server that sends no notification, or an automatic reply (RFC 3834). From it, it takes each recipient, the enhanced status code (RFC 3463), the kind of bounce — hard, soft, complaint, automatic reply, success —, the action for the application, and the message it is about, by its Message-ID, its Feedback-ID, a field of the application's own, or the tag of a VERP return path. Rules the application declares, in their order, decide what no standard describes.

It is for any PHP application that sends mail through its own SMTP server and reads the bounces from a mailbox: a newsletter, the notifications of a site, a mailing list. It turns the bounce mailbox into counters of hard and soft bounces, unsubscriptions on complaints, and a short queue of messages for a person to read.

It is a plain PHP library whose requirements are ext-ctype, ext-iconv, ext-mbstring and ext-sodium. Its MIME reader never throws, whatever the message holds, and bounds its work: octets read, depth, parts, header fields and text. An abuse report unsubscribes only when an authenticator vouches for it.

The design: Mime\MimeParser reads the message into Mime\Parts; BounceParser recognises the report and returns a BounceReport — ReportFormat, BounceKind, BounceAction, the Recipients with their StatusCode, the FeedbackReport, the OriginalMessage —, then tries the Rule\Rules; Verp writes and reads return paths; Contract\ReportAuthenticator vouches for abuse reports.

Status

Part State
MIME: header fields, encoded words, media types, base64, quoted-printable, multiparts, held messages, digests Implemented and tested
Delivery status notifications (RFC 3464, RFC 6533): every recipient, action, status, diagnostic, SMTP code Implemented and tested
Enhanced status codes (RFC 3463): parsing, finding in text, failures about the message rather than the mailbox Implemented and tested
Abuse feedback reports (RFC 5965, RFC 6591): every field, complaint or not Implemented and tested
Authentication of reports: Authentication-Results of the application's server, or trust every report Implemented and tested
Bounces written as text: sender, subject, first address, first status or SMTP code Implemented and tested
Automatic replies: Auto-Submitted, X-Autoreply, X-Autorespond, Precedence: auto_reply Implemented and tested
The message a report is about: Message-ID, Feedback-ID, any field, In-Reply-To of a reply Implemented and tested
VERP return paths: signed tags, tags and classic recipient encoding Implemented and tested
Rules on the subject, the sender, the text, the diagnostics or a field, ordered by name, each with its action Implemented and tested
Proposed rules for unrecognised messages Not started: a bundle's work, with its review queue
Reading a mailbox (IMAP, POP3, mbox) Not started: a bundle's work; the library takes one message as text

Documentation

Document What it covers
Installation Requirements, installing, the parser as a service.
Parsing What the parser recognises, in which order, and the report it returns.
Kinds and actions How a bounce becomes hard or soft, and the action of each kind.
Status codes StatusCode, its class, subject and detail, and the failures about the message.
Feedback reports Abuse reports, their fields, and the authenticators.
Finding the message OriginalMessage, Feedback-ID, the application's own field, and VERP.
Rules Declaring rules, their fields and scopes, ordering them, and their actions.
MIME The MIME reader used on its own, and its limits.
Threats What a hostile message can attempt, and what the library and the application do about it.
Extension points The port, the arguments and the rules an application chooses or replaces.
Testing The library's tests, fuzzing and mutation bar, and how to test code that reads bounces.
Reference Every type of the library, with its role.

Quick start

composer require phil/bounce-parser
use Phil\BounceParser\Auth\AuthenticationResults;
use Phil\BounceParser\BounceAction;
use Phil\BounceParser\BounceKind;
use Phil\BounceParser\BounceParser;
use Phil\BounceParser\Rule\Field;
use Phil\BounceParser\Rule\Rule;
use Phil\BounceParser\Rule\Rules;
use Phil\BounceParser\Verp;

$verp = new Verp('bounces', 'mail.example.net');
// Each message is sent with its own return path: $verp->encode($messageId).

$parser = new BounceParser(
    rules: new Rules(Rule::containing('quota', Field::Body, 'over quota', BounceKind::Soft)),
    verp: $verp,
    authenticator: new AuthenticationResults(['mail.example.net'], ['fbl.example.com']),
);

$report = $parser->parse($rawMessage);

$report->kind;            // BounceKind::Hard
$report->action;          // BounceAction::CountHard
$report->addresses();     // ['ada@example.org']
$report->verpTag;         // the identifier the message was sent with
$report->recipients[0]->status?->toString(); // '5.1.1'

Requirements

PHP 8.5 or later, ext-ctype, ext-iconv, ext-mbstring and ext-sodium.

Contributing

Contributions are welcome on the PHIL monorepo: read the contribution guide and the code of conduct. Report a vulnerability privately, as the security policy explains, never in a public issue.

License

MIT, © Philippe Gamache, doing business as Le Gnome Archiviste; a Parler Haut Interagir Librement project. See LICENSE.