Skip to content

Rules

phil/bounce-parser

A rule is the application's answer to a message no standard describes: a pattern on one field of the message, the kind of bounce it means, and the action it leads to.

use Phil\BounceParser\BounceAction;
use Phil\BounceParser\BounceKind;
use Phil\BounceParser\Rule\Field;
use Phil\BounceParser\Rule\Rule;
use Phil\BounceParser\Rule\Rules;
use Phil\BounceParser\Rule\RuleScope;

$rules = new Rules(
    Rule::containing('quota', Field::Body, 'over quota', BounceKind::Soft),
    Rule::matching('gone', Field::Body, '/account (has been )?(disabled|closed)/i', BounceKind::Hard, BounceAction::Suppress),
    Rule::containing('ticket', Field::Header, 'helpdesk', BounceKind::AutoReply, header: 'X-Mailer'),
    Rule::containing('policy is gone', Field::Diagnostic, 'user does not exist', BounceKind::Hard, scope: RuleScope::Always),
);

Declaring

ConstructorPattern
Rule::matching($name, $field, $pattern, $kind, $action, $scope, $header)A PCRE regular expression with its delimiters and flags
Rule::containing($name, $field, $text, $kind, $action, $scope, $header)A text the field contains, without regard to case, in UTF-8

The action defaults to the action of the kind (BounceAction::for()). A pattern that is not a valid regular expression, an empty text, or a rule on Field::Header without a field name throws Exception\InvalidRule when it is declared, not when a message arrives. A pattern that fails on a message — too much backtracking, broken UTF-8 — does not match it.

Fields

FieldThe text
SubjectThe subject, its encoded words decoded
FromThe From field as written
BodyThe text parts of the message, not those of the message it returns, one after the other, up to the limit of text
DiagnosticThe diagnostics of the recipients of a delivery status notification, one a line
HeaderEvery value of the named field, one a line

Scopes

RuleScopeThe rule is tried on
Unrecognised (default)Messages whose kind is unknown: unrecognised, a bounce written as text without a code, a notification without a recipient
AlwaysEvery message, so that it may correct what the parser decided

Order

The rules are tried in their order, and the first that matches decides: the report keeps its format and recipients, and takes the rule's kind, action and name. Rules::with($rule) adds a rule at the end; with($rule, before: 'name') and with($rule, after: 'name') place it next to a rule by name — before wins when both are given. Nothing is ordered by number. Two rules of one name, or a name to place by that does not exist, throw Exception\InvalidRule.

Writing a rule from a message

A message left for review holds the words a rule needs: the server's sentence in its text, its subject, or a field it adds. Write the narrowest text that names the case, try the rule against the messages kept for review, and keep the rules few: each costs a match on every message of its scope.