Files
warmbly/internal/client
Matthew Meszaros 1b8c51ad06 feat: read spam complaints and domain-auth refusals, the last two open delivery signals (#232)
* feat: close the two halves of the delivery-signal loop that were still open, complaints and domain-auth refusals: a spam complaint arrives as mail long after the send succeeded, and nothing read those reports, so the strongest negative signal a sender gets never reached the complaint rate, the suppression list or the breaker; internal/pkg/arf parses RFC 5965 feedback reports worker-side alongside the existing DSN path, takes the LAST Message-ID because the reported mail's headers follow the report's own, and records only abuse-type reports so a not-spam report cannot be inverted into a complaint; separately a receiving server refusing mail because the SENDING DOMAIN failed its authentication (5.7.515, 5.7.26) was classified as SERVER_UNREACHABLE and retried forever, and it is now its own hard code that blames the domain rather than the address, leaves the recipient unsuppressed, and brings that domain's DNS re-check forward so the sweep confirms the verdict the send gate acts on

* feat: make the complaint path actually reachable, and stop it trusting the report: selectTextParts only ever picked text/plain and text/html, so an RFC 5965 report's message/feedback-report and message/rfc822 parts never reached the worker and both Feedback-Type and the reported Message-ID were invisible, which would have left this feature inert and has been quietly weakening DSN parsing too; report parts are now selected as plain text; the complainer is taken from the RESOLVED SEND rather than the report body, because a report is unauthenticated mail anyone able to reach the mailbox could forge and honouring the address it names would let a forger suppress a contact the send never went to; Original-Mail-From is no longer read as the complainer since that address is the sender; and a domain-auth refusal now releases the reservation instead of spending one of the lead's attempts, because the recipient received nothing and the problem is the mailbox's domain, so another mailbox in the pool picks the lead up

* feat: fix the same missing-parts gap in the Gmail adapter, and say plainly that Microsoft Graph cannot see reports at all: goog.extractBody took only text/plain and text/html exactly as the IMAP path did, so a feedback report synced from Gmail was as invisible as one synced over IMAP, and the tests that would have caught either called the parser directly rather than going through the adapter where it actually broke; the new tests exercise that seam, and Graph returns one rendered body with no parts so reports there are undetectable without a MIME fetch that is not built, which the docs now state rather than implying full coverage
2026-08-28 11:02:45 -07:00
..