• v0.45.0 a2436cfb11

    v0.45.0 Stable

    joeyr released this 2026-08-25 15:41:16 -05:00 | 72 commits to main since this release

    Mail that arrives through a forwarder is now judged by who actually sent it.
    56% of the sampled inbox is relayed, and every check that reads the sending
    domain was reading the forwarder. Also fixes a DKIM property name that had the
    RFC 8058 coverage check inert on the whole Gmail tenant.

    Added

    • mail/origin.py — recovers the original sender from behind a forwarding
      hop, shared by both tenants. Origin carries the domain to judge, a
      provenance (direct / relayed / relayed_unresolved), the relay, and
      whether the answer is a claim.

      The design this replaces read the ARC chain, and it could not have worked.
      RFC 8617 puts the first relay's record of the original sender's
      authentication in the i=1 ARC-Authentication-Results. On all 228 relayed
      messages sampled, that header reads in full: i=1; mail.protonmail.ch — an
      authserv-id and nothing else. The chain validates and carries no verdicts
      inside it. A resolver written against it returns "the original failed
      authentication" for every forwarded message, and since that is a blocking
      signal it would have refused 28 of 28 relayed unsubscribe offers where 21 are
      allowed today. Measured before the module was written.

      What is available is the rewritten From — shaped "Example Store - hello at store.example" <hello_at_store_example_TOKEN@RELAY> — carried in the display
      half on 228 of 228 and the local part on 117. Reading it is the same
      trust decision as trusting the relay's ARC seal: same domain, same key, same
      notary. It is not read without the relay's own verified DKIM signature over
      From, present on 232 of 232 signatures sampled.

      The downgrade is coverage, not trust, and it bounds the feature. The chain
      would have carried a verdict; the rewritten From carries a claim. So
      Origin.claimed is always true on relayed mail, the output says so in a
      sentence, and the unsubscribe gate was deliberately not retiered on
      "authenticated origin" — that question has no input on this account.

      TRUSTED_RELAYS is simplelogin.co and duck.com, both from observation.
      A third was expected and appears on zero of 400 messages, so it is not there.

    • origin in get_message_security on both tenants, always present so the
      shape does not change between direct and relayed mail. The chained-relay case
      is live and handled: privacy.example → simplelogin.co → duck.com reports
      the origin, not the previous hop, because a candidate that is itself a relay
      is a hop rather than a sender.

    Fixed

    • The RFC 8058 signature-coverage check was inert on the entire Gmail
      tenant.
      MethodResult.domain looked for header.d; Gmail reports the DKIM
      domain as header.i and never as header.d — 492 of 492 verdicts
      sampled. So the property returned "" for every DKIM verdict there, which
      meant unsubscribe._verified_signatures found nothing, headers_are_signed
      returned None rather than a verdict, and all 48 one-click offers were
      reported as signature_coverage_unknown instead of being checked. The
      security report also showed a DKIM pass with no signing domain.

      Fixing it turns one message from allowed into correctly refused: a sender
      whose signature covers List-Unsubscribe but not List-Unsubscribe-Post,
      which RFC 8058 §3.2 requires for one-click.

    • brand_mismatch judges the recovered origin. Seven relayed Facebook
      messages were refused for impersonating Facebook — they came from
      facebookmail.com through SimpleLogin, and the check saw simplelogin.co.
      Relayed unsubscribe offers go from 21 allowed / 7 refused to 28 / 0 on the
      sample, with no direct-mail decision changed.

      _reply_to_mismatch is deliberately left alone: under relaying both From
      and Reply-To are the relay, so it compares a domain against itself and is
      silent rather than wrong — and it is non-blocking, so a misfire costs a
      warning.

    Changed

    • authresults.summarise names the relay and refuses to lend it the sender's
      credibility.
      Untreated it reported "the message really was sent by
      'simplelogin.co'"
      — true and useless — beside a DMARC policy note describing
      the relay's published policy as though it were the sender's. That is
      false reassurance rather than a false alarm: a brand mismatch is visible when
      it misfires, a strong policy attributed to the wrong domain is not.
    Downloads