9.8 KiB
SMTP comparison with Postfix 3.11.1
This review uses the unmodified Postfix 3.11.1 source tree as a behavioural
reference for every SMTP test in release-testing-0.7.md. It is a source
review, not a substitute for a successful Bongo live test. A test remains
open in the release matrix until its Bongo fixture has passed.
The comparison deliberately follows public SMTP, LMTP, XCLIENT, XFORWARD and HAProxy PROXY behaviour. Private Postfix queue protocols and implementation details are not copied.
Previously reviewed cases
These cases already have a Postfix comparison in the named Bongo documentation and were not reviewed a second time:
| Tests | Existing comparison |
|---|---|
| SMTP-07, SMTP-08, SMTP-27 | tls.md and the matching sections in test-evidence/0.7-r1.md |
| SMTP-11, SMTP-12, SMTP-13 | Matching sections in test-evidence/0.7-r1.md |
| SMTP-14 | Postfix DSN command generation and recipient-state handling were used for the implementation review; the Bongo live test is still open |
| SMTP-32, SMTP-33 | smtp.md and the matching sections in test-evidence/0.7-r1.md |
SMTP server and submission
| Tests | Postfix reference | Bongo comparison |
|---|---|---|
| SMTP-01 | src/smtpd/smtpd.c: command table, smtpd_proto(), helo_cmd(), vrfy_cmd(), etrn_cmd() |
Bongo has the same transaction boundaries and one reply per command. Its VRFY policy is privacy-preserving and configurable, as with Postfix's disable_vrfy_command. |
| SMTP-02, SMTP-03 | conf/master.cf: separate submission and submissions services; src/smtpd/smtpd.c: STARTTLS and SASL gates |
Bongo likewise separates port 587 STARTTLS from port 465 wrapper TLS and does not expose plaintext credentials before the configured TLS boundary. |
| SMTP-04, SMTP-05 | src/smtpd/smtpd_check.c: permit_mynetworks(); src/smtpd/smtpd.c: client message and recipient rate limits; ADDRESS_REWRITING_README: canonical maps |
Bongo's port 26 is a deliberate integrated equivalent for constrained devices. Unlike Postfix's default exemption for mynetworks, Bongo continues to rate-limit trusted devices. DNS/IP sender normalisation is applied only on that configured trust boundary. |
| SMTP-06 | Postfix separates SMTP reception, cleanup rewriting and outbound transport; outbound signing is normally a Milter policy | Bongo records local origin explicitly and applies DKIM/SRS only when the message crosses an external transport. Local authenticated delivery therefore remains byte-stable apart from normal transport headers. |
| SMTP-10 | src/smtpd/smtpd_check.c: reject_unauth_destination(); default smtpd_relay_restrictions |
Bongo has the same essential invariant: an unauthenticated client outside a trusted network may submit to hosted recipients, but not relay between two third-party domains. |
| SMTP-15, SMTP-16 | README_FILES/BDAT_README; src/smtpd/smtpd.c: bdat_cmd() |
Like Postfix, Bongo advertises CHUNKING without BINARYMIME, consumes every declared chunk boundary, handles BDAT 0 LAST, drains known-size rejected chunks, and never advertises or accepts BODY=BINARYMIME. Bongo also bounds temporary storage instead of buffering an unbounded chunk in memory. |
| SMTP-17 | README_FILES/SMTPUTF8_README; src/smtpd/smtpd.c: SMTPUTF8 MAIL/RCPT checks; src/smtp/smtp_proto.c: peer capability check |
Bongo requires valid UTF-8 when SMTPUTF8 is selected, rejects non-ASCII envelopes or internationalised headers without it, and requires a capable next hop. Bongo additionally rejects a non-conforming peer that advertises SMTPUTF8 without its mandatory 8BITMIME companion. |
| SMTP-26 | src/global/midna_adomain.c, src/smtp/smtp_addr.c, src/smtpd/smtpd_check.c; SMTPUTF8_README IDNA section |
Both implementations convert Unicode domains to an IDNA2008 A-label at DNS and policy boundaries. Bongo uses the same canonical A-label in aliases, SMTP routing, configuration and Web compose so equivalent Unicode spellings cannot create distinct routing identities. |
| SMTP-30 | Postfix smtpd(8) accepts standards-compliant SMTP independently of client implementation |
Bongo's fixture covers five independent clients and paced manual Telnet input. No Bongo-only command or timing assumption is required. |
Recipients, aliases and forwarding
| Tests | Postfix reference | Bongo comparison |
|---|---|---|
| SMTP-18 | src/smtpd/smtpd.c: rcpt_cmd(); src/cleanup/cleanup_out_recipient.c: recipient expansion and duplicate filtering |
Bongo keeps status per RCPT, permits accepted and refused recipients in one transaction, and expands aliases without duplicating an already expanded destination. DATA is accepted only when at least one recipient remains. |
| SMTP-19 | ADDRESS_REWRITING_README: canonical and virtual alias maps; src/trivial-rewrite/resolve.c: bounded rewrite loop; src/smtp/smtp.c: delivered-header loop detection |
Bongo applies bounded address/domain aliases and detects forwarding loops. Postfix core has no equivalent integrated SRS implementation, so Bongo's libsrs2 boundary is intentionally additional: SRS is added only when forwarding an external sender externally and decoded only for a valid local SRS return address. |
Outbound SMTP and relayhost
| Tests | Postfix reference | Bongo comparison |
|---|---|---|
| SMTP-09 | src/smtp/smtp.c; SASL_README: relayhost, optional smtp_sasl_auth_enable, optional port and TLS policy |
Bongo supports a relayhost with or without authentication, explicit port, opportunistic/required/verified TLS and wrapper TLS. A failed connection or authentication attempt leaves the message durably queued. DKIM/SRS preparation is shared with direct-MX delivery. |
| SMTP-22 | XCLIENT_README, XFORWARD_README; src/smtpd/smtpd.c: cached authorization; src/smtpd/smtpd_proxy.c: negotiated attribute subset |
Bongo emits only attributes advertised by the destination and only to configured trusted destinations. After XCLIENT's required 220 reply it performs a fresh EHLO before delivery; XFORWARD retains the current SMTP transaction state. The trust lists name downstream servers and never authorize inbound clients. |
| SMTP-23 | man/man5/access.5 and src/smtpd/smtpd_check.c: PREPEND before the Received header |
Some appliances cannot speak XCLIENT/XFORWARD. Bongo's fallback header is the narrower equivalent: it is generated only for explicitly configured trusted peers and cannot be supplied by an untrusted client as authoritative connection metadata. |
LMTP
| Tests | Postfix reference | Bongo comparison |
|---|---|---|
| SMTP-20 | src/smtp/smtp.c: shared SMTP/LMTP client with separate destination lookup and LHLO |
Bongo also uses the normal queued outbound client with an explicit LMTP route. The internal transport preserves the envelope and bypasses Internet-only DKIM/SRS preparation. |
| SMTP-21 | src/smtp/smtp_proto.c: LMTP SMTP_STATE_DOT loop; src/smtp/smtp_rcpt.c: mark/sweep recipient accounting |
Bongo waits for exactly one final reply for every recipient accepted before message data. A 2xx recipient is completed, a 4xx recipient remains queued, and a 5xx recipient is failed independently; completed recipients are not redelivered on retry. |
Connection metadata and abuse resistance
| Tests | Postfix reference | Bongo comparison |
|---|---|---|
| SMTP-24 | src/smtpd/smtpd_haproxy.c and src/global/haproxy_srvr.c |
Bongo accepts PROXY v1/v2 only before SMTP framing and only from configured proxy networks. Malformed or unsolicited proxy data fails the connection instead of becoming an SMTP command or client identity. |
| SMTP-25 | src/smtpd/smtpd.c: line_length_limit, soft/hard error limits, junk command limit, per-record deadline and timeout |
Bongo bounds command lines, payload sizes, error counts and idle time. For a malformed BDAT size, where the next command boundary is unknowable, it closes the connection. Known-size rejected chunks are consumed before command parsing resumes. |
| SMTP-31 | src/postdrop/postdrop.c; QSHAPE_README: unprivileged sendmail to protected maildrop and pickup |
bongopostdrop follows the same privilege split: the user-facing sendmail process does not read Bongo's system credential, incomplete files are not deliverable, signals clean partial files, and only the protected handoff makes a complete message visible to the queue. |
TLS reporting
| Tests | Postfix reference | Bongo comparison |
|---|---|---|
| SMTP-28 | README_FILES/TLSRPT_README; src/smtp/smtp_tlsrpt.c: policy lookup and DANE/STS/connection/EHLO event data |
Bongo preserves the exact policy that governed the attempt and aggregates immutable, completed UTC days into RFC 8460 JSON. As in Postfix, the event belongs to the policy domain and final TLS outcome, not to a later queue result. |
| SMTP-29 | TLSRPT_README: Postfix delegates collection and report generation to libtlsrpt and tlsrpt-reporter |
Bongo intentionally keeps equivalent reporting in bongoworker: gzip mail/HTTPS delivery, DKIM on report mail, randomised dispatch, durable retry and expiry. Report messages are marked and excluded from recursive TLSRPT generation. This is an architecture difference, not a wire-protocol difference. |
Review result
No missing public Postfix SMTP extension was found that invalidates the 0.7 matrix. Bongo intentionally differs in four places:
- trusted-device port 26 includes normalisation and remains rate-limited;
- SRS is integrated instead of delegated to an external service;
- SMTPUTF8 peers are checked for the RFC-mandated 8BITMIME companion;
- TLSRPT aggregation and delivery are integrated instead of delegated to the sys4 reporter.
The historical queue consumer in bongosmtp was not part of any of these
paths. bongosmtpc is the sole active outgoing Queue consumer; the retired
consumer is compile-time disabled so it cannot silently diverge from the
reviewed implementation.