On Tue, Oct 6, 2026, at 13:26, Stephen J. Turnbull wrote:
> Bron Gondwana via Mailman-Developers writes:
> 
> > Yes, I'm sorry I should have pulled the Mailman community in
> > earlier.  I didn't want to drag you through the really early stages
> > of "we're not even sure which headers need to be signed" pre-IETF
> > discussions, and of course since the work went to the IETF,
> > everyone is welcome!  You don't need an invite.
> 
> I've participated in IETF WGs before.  I am just getting out of Google
> Summer of Code mode, which as org admin and mentor takes a lot of
> energy.  Also, the last I looked the draft had expired about 6 months
> previously, IIRC.  So didn't seem urgent.

You're not the first person to have this misconception, so we're clearly doing 
something wrong!  The IETF DKIM working group adopted a different document, 
which has been progressing with frequent updates:

https://datatracker.ietf.org/doc/draft-ietf-dkim-dkim2-spec/

The most recent published version was 06 on August 28, but we had an interim 
meeting a couple of weeks ago and version 07 should be dropping any day now.

> 
> > There is a way to [spell "trust me"] with DKIM2 (for the body, you
> > can't do valid DKIM2 at all without describing all your header
> > field changes), but it's strongly discouraged.  The whole point of
> > DKIM2 is to avoid having to trust anyone, because you can verify
> > what they did.
> 
> Sure, but that's not a Mailman site's problem if they are trusted.  It
> only matters if receivers or gateways decide to be persnickety.

That's true, but I would imaging that most mailing lists aren't auto-trusted by 
all recipients.  They'll often have people with Gmail or Yahoo accounts on 
them, both of whom are planning to start enforcing DKIM2 at some point (and 
Fastmail as well, but I don't hold any unrealistic expectations about our 
relative clout compared to those two).

> BTW it's not clear to me how much you actually gain, because once the
> message is edited somewhere on the wire, receivers either have to
> verify that the edited message doesn't contain malicious content, or
> they have to revert and lose the value-add of the intermediary.  That
> latter will likely piss off end users.  I kinda wonder how many sites
> will spend the cycles on reconstructing original messages.

The idea is more that you check if the message is spam.  If it isn't, then you 
don't assume that some intermediate site took a bad message and cleaned it up.

The issue is the other side - a message that IS spam, you can reliably undo the 
changes that the mailing list did, and check whether the mailing list is a real 
mailing list that happened to have spam sent to it, or a fake mailing list 
which is really just pretending it got the original message and then sending 
out spam instead.  You can't really distinguish that with DKIM, because you 
take a perfectly legit email's headers, replace the content entirely, and 
pretend you're a list which just rewrote the subject and added a signature.

> That's an honest question, I would like to hear your data or opinion
> on it.

My opinion is "without undo capability, you have to build a trust database of 
everything which claims to be a mailing list in the entire world -- with undo 
capability, you just have to check a spam to see where the badness was 
introduced".

> > > Does this (and other such changes) require monkey-patching the
> > > Python email package?
> > 
> > Actually no.
> 
> Good!
> 
> > It's purely within decorate.py.  The simpler method would be to
> > always use MIME wrapping for DKIM2-signed incoming messages, but
> > there's a reason why mailing lists don't just do that with every
> > message anyway.
> 
> I'm not sure those reasons really apply any more, at least not to our
> primary user base.  There are specialized lists that most feed
> machines, but those usually set Mailman to "never edit" (except for
> trace headers and maybe List-* headers).

Yeah, the List-* headers is easy enough - you just create a recipe which strips 
them in the Message-Instance that you add.

Here's an example Message-Instance from a list which I run at mailman.dkim2.com:

Message-Instance: m=2; 
h=sha256:yZ0VimAZoYVv7yEIgtyniRSQASld1tnU11rz525iWo4=:andIp9TdE99Ce2Wv/qw9SfkMGD3dXhDf7xWoveKW300=;
 
r=eyJoIjp7ImFyY2hpdmVkLWF0IjpbXSwiY29udGVudC10eXBlIjpbeyJkIjpbIm11bHRpcGFydC9hbHRlcm5hdGl2ZTsgYm91bmRhcnk9MzYzNjk0N2QyYjA0M2U1MjUzOTc2YzE3ZTY1Mzk1MGUwMDcwNjBhMiJdfV0sImxpc3QtYXJjaGl2ZSI6W10sImxpc3QtaGVscCI6W10sImxpc3QtaWQiOltdLCJsaXN0LW93bmVyIjpbXSwibGlzdC1wb3N0IjpbXSwibGlzdC1zdWJzY3JpYmUiOltdLCJsaXN0LXVuc3Vic2NyaWJlIjpbXSwibWVzc2FnZS1pZC1oYXNoIjpbXSwicHJlY2VkZW5jZSI6W10sInN1YmplY3QiOlt7ImQiOlsiSGVsbG8gZGtpbTIgbGlzdCJdfV19LCJiIjpbeyJjIjpbNSwyM119XX0=;

h= are the hashes of the output headers and body, r= is the recipe, which is 
base64 of the following JSON:
{
  "h": {
    "archived-at": [],
    "content-type": [
      { "d": [ "multipart/alternative; 
boundary=3636947d2b043e5253976c17e653950e007060a2" ] }
    ],
    "list-archive": [],
    "list-help": [],
    "list-id": [],
    "list-owner": [],
    "list-post": [],
    "list-subscribe": [],
    "list-unsubscribe": [],
    "message-id-hash": [],
    "precedence": [],
    "subject": [
      { "d": ["Hello dkim2 list"] }
    ]
  },
  "b": [
    { "c": [ 5, 23 ] }
  ]
}

Which basically says "replace all the named headers with the list of headers 
described by the array of values" - for most that's no instances, so they get 
stripped.

The content-type needs to get the old boundary, and the subject gets the old 
un-prefixed value.

And for the body it says keep (copy) lines 5 through 23 of the output message 
to re-create the input message.

> > The existing wrapper code in decorate.py explicitly takes any
> > existing CTE and rewrites the part as unicode.  I GUESS we could
> > have the email package have a mode which took that and
> > back-converted it identically, but that seems very inefficient at
> > best.
> 
> The point of the email package is to work with a structured object
> that is efficient for programmers.  Some transformations from wire
> format to user-friendly representations are not reversible in
> principle (for example, Unicode equivalent normal forms for composed
> characters).  So for DKIM2 purposes we must store the wire format
> anyway (perhaps in encoded form, such as storing the positions of
> folding white space in a header field with the unfolded field).

DKIM2 doesn't care about exact whitespace in headers - it uses the relaxed 
canonicalisation, so you can fold multiple spaces to a single space, or expand 
a single space to multiple including a line wrap.  You can't add spaces where 
there were none before though.

> > Yes, the changes description just needs to know the number of lines
> > to copy from the output data to recreate the input data; and (if
> > any lines are changed) it has to include the input version of that
> > line.  It's basically an "undo" diff.
> 
> Which in the case of Mailman might be 100MB of deleted attachment.

Yeah, lists which deletes attachments 100% will just have to turn off dkim2; or 
we'll need to add a "null body recipe" mode for them, which declines to 
describe the body changes.

> > If the CTE is changed, then that's a header diff, and the
> > description of that will be included in the header recipe.
> 
> Aha!  That's helpful for my understanding.  Makes sense, that's how
> DKIM 1 would do that kind of thing.
> 
> > Worst case (without adding ANY support to Mailman at all) my
> > wrapper milters capture the message on the way in, and on the way
> > out.  You can diff ANY two sets of data of course, so you can
> > calculate the diff - but the more that Mailman re-encodes and
> > fiddles with things, the bigger the diff.
> 
> I am just not worried about 40kb text diffs, though I guess that may
> piss off MTA maintainers.  Not in a world where Outlook takes 4kb of
> text/plain and appends 40kb of text/html.  I guess recipient domains
> might like to save a handful of cycles per message, but, uh, what's in
> it for Mailman sites?

The problem is that the 40k goes into a header field, which - even with 
wrapping is still going to start hitting header limits.  You're much better 

> > A lot of this pre-cursor work is just reducing the size of the diff
> > to the smallest manipulation required.
> 
> Sure, I understand that.  You're using Mailman's CPU for that, though.
> We didn't ask for it, why should we pay for it?

I mean, that's a take.  You didn't ask for DKIM1 or DMARC either, yet plenty of 
mailman sites wind up rewriting From addresses because they have to operate 
with the rest of the world. 

It's not 1997 any more and the amount of CPU involved here is, I believe, 
incredibly trivial, even on low powered boxes.

I'd be happy to benchmark it against a corpus of representative email if you 
have one handy.  I've only been testing against my own collections of email 
which may not match common usage patterns.  Do you have an existing Mailman 
performance suite I could use?

> > >   I'm not sure I like the implications of multiplying the
> > > storage requirements for large messages that way, especially for
> > > resource-constrained instances (eg, living in a Linode Nanode). 
> > 
> > Do you mean storage requirements for the archive, or storage
> > requirements during the message transit?
> 
> The archive isn't a problem, we just strip out the DKIM2 diff data
> before storing if it is (most archivers strip the trace headers
> anyway).  I'm talking about RAM and message queue storage.  In
> particular, many sites run multiple out queues, and bloating the
> messages with diff data could get runners oom-killed.  Also output and
> archive queues often end up with with dozens of message objects in
> them for one reason or another, you could fill the disk much faster.
> People really do run Mailman in ~1 vCPU + 2GB + small /var, and
> hosting sites do care about bloating message objects because they run
> on thin margins -- cost of storage matters to them.

As you saw in my example above.  The diff data was shorter than some Message-Id 
headers I've seen in the wild!  Yes, you need to do a separate email per 
recipient (but people using VERP already do that), which might be more of a 
space usage issue for lists on really small hardware I guess.

My "dkim2.com" test machine is running on a single CPU, 2 GB instance 
deliberately so I see how it performs.  I'll definitely run any benchmarking on 
that as well as my rather more powerful laptop.

> > > And I know of at least two sites with lists whose content
> > > frequently includes large (GBs) attachments.  (Yes, I have seen
> > > multimegabyte files QP-encoded, although my correspondents are
> > > too polite to send me GBs of attachments so I can't testify to
> > > that level of aggravation.)
> > 
> > That shouldn't cost any more if those parts aren't edited - the
> > lines will just be copied verbatim.
> 
> You're missing the point: bandwidth for the Mailman site and disk
> storage for all list subscribers.  I do not want Mailman to be a copy
> machine for everybody's 4k pet photos (unless the list owner wants
> that).  *Especially* if nobody will actually see the cute kitties!

I am persuaded that we need to add a mode to the Mailman patchset to allow such 
sites to configure "strip attachments and include a NULL body recipe" - and 
those sites can continue to run in that mode indefinitely (until too many 
receivers start rejecting NULL recipes anyway; which will be years away)

> > Strictly, DKIM2 treats the body like an array of lines.  We did
> > think about doing MIME-structure based recipes. There are some real
> > advantages to understanding the structure better, but we concluded
> > that the added complexity didn't earn its keep.
> 
> Not surprised.  Not sure what could be done with it myself (you'd
> really have to DKIM sign each part separately for "edits by part"
> functionality, and I suspect that would be a huge can of worms).

I know.  It's a pity, but that would be a huge complexity add for everyone, 
while working in lines is pretty trivial.

> > But this leads to another point.
> > 
> > > Obviously, it is at best highly undesirable to include those
> > > deleted parts verbatim in a change description.
> > 
> > Deleting parts is a sin.
> 
> So is sending messages that violate list policy.  If people do that
> inadvertantly, why not strip the part and get the conversation going?
> This is a common situation on Mailman lists, with people sending us
> incident reports with screenshots of error messages and the like.
> They are *very* grateful to get some analysis back immediately even
> though they have to convert their screenshots to text etc. in their
> next post.

OK.  I agree.   BUT.  (and it's a bit BUT)

This is the hole that spammers sneak through.  My number one goal that I 
describe everything in DKIM2 as being for is "reduce the grey areas".  These 
are the places where legitimate email and spam are indistinguishable.  Things 
like "you can BCC somebody with no evidence anywhere in the message that they 
were BCCd" is how DKIM replay works.  That's a grey area.  It's perfectly 
reasonable... and why should I have to take my pocket knife out of my carry-on 
when I get on a plane, I'm not planning to hijack the plane.  This rule isn't 
there to block that use case, it's to block the security hole which allowing 
that use-case to exist creates for everyone; because they have to work out if 
it was that case rather than having a hard rule "if you didn't describe what 
you did then you have to take ownership of the message".  You can always strip 
the existing DKIM2 and start the message from clean, but you're definitely 
rewriting the "From" address then.

> > A list which strips attachments should probably just not
> > participate in DKIM2; or should re-originate the message (strip any
> > existing DKIM2, and just start with a hashes-only
> > `Message-Instance: m=1` on egress).
> 
> So we're back to "trust me", or lose a value-added service.  Once
> again, ongoing burdens are imposed on mailing lists.

Do you have an alternative solution?  Because I haven't been able to come up 
with one.  If you do, I'm all ears.  Otherwise this seems to be "I want to keep 
doing things which are a known spam vector" and that's going to hurt mailing 
lists even more because they'll get blocked out entirely.

> > Otherwise yes, you need to describe the entire attachment.  At that
> > point your choice is either to encode it in the recipe (which will
> > make the header ungodly long) or hide it in the MIME postamble.
> > Either way, the wire size will still include the entire size of the
> > attachment, negating most of the benefits of stripping it in the
> > first place.
> 
> No, the wire size will be the entire size of the attachment times the
> size of the list.  Are you starting to see our problem?

Yes, you can't do that.  Hence the "null recipe" option.

> > > In any case where a message violates site or list policy but
> > > without DKIM2 we could massage it into conformance, we will have
> > > an option to reject it.
> > 
> > Indeed, you always have that possibility!  Or to forward it without
> > adding DKIM2 -- at least while the world still allows that.
> 
> Well, yeah, that's the problem.  The world by and large is happy to
> sacrifice mailing list affordances for dubious improvements to spam
> filtering that mostly benefit the large freemailers, and companies
> that don't want to restrict sending from p=reject addresses to
> transactional mail flows.

I run an email list service.  I'm really keen to make this work for mailing 
lists.  I don't understand why you think this is bad for mailing lists.  
Freemailers aren't getting much out of this, it's really designed to make 
mailing lists remain viable!  Otherwise we wouldn't have bothered with recipes 
at all and just said "no changes allowed, deal with it!"

> I don't see any point to nonparticipation in DKIM2.  I like the
> improvements to the chain of custody.  We are not always the last hop
> in the chain.  DKIM2 clearly has some value to Mailman sites.  But the
> requirement for reproducibility of the original so that original
> signatures can be verified is going to be painful for some lists if
> recipient domains require that.

Yes, it will.  I just don't see what else we can do for those lists other than 
either require them to be registered in some "trusted lists" registry or accept 
that every spammer can pretend to be one of them.

> > > To me, this all looks overengineered.  
> > 
> > Yes, it is a little.  It's done that way for a reason, to make sure
> > we minimise the amount we change the lines on the wire.  Certainly
> > just going straight to MIME wrapping for everything works (it was
> > my first pass); and I'd be very happy for that to be an answer that
> > everyone was happy with.
> 
> OK, we have a starting point.  Before you spend your time on reviewing
> generated code etc, we should talk about what you do want beyond the
> bare minimum we seem to agree on already, because I know a lot about
> mailing lists you want to know.  For example:
> 
> > You probably know better than me how many lists just MIME-wrap
> > everything.
> 
> Basically, no Mailman lists do that for *everything*, because Mailman
> MIME-wraps only when it has to.  That's almost all the time these days
> (most people send HTML mail), but there are still a lot of weirdos
> like me who tell their MUAs to ignore rich text in favor of text/
> plain, and send almost all their mail as text/plain -- such posts
> don't get wrapped, they get prepended and appended, maybe with a
> change in the charset parameter or CTE.
> 
> However, as I said above, pretty much all subscribers can handle
> wrapping the original and prepending a header (uncommon AFAIK) and
> appending a footer (close to universal due to CAN-SPAM, GDPR, etc).
> And for any who can't, the wrapped version is ugly but readable for
> text/plain 7bit/8bit, and the rest are unreadable anyway.  (In theory
> text/html could be readable, but hey, Microsoft MUAs, ya know?)
> 
> So in practice, "MIME-wrap a lot" to "MIME-wrap all DKIM2" is not a
> big change, I think.  But we'll see.  That's why options rule.

In that case, that seems like a great first pass!  We can always come back and 
re-engineer the non-wrap codepath later if there's demand.

> > If that's the future, then I'm all in favour.
> 
> I think it's a good idea to start there, and see if any users notice.
> In any case, how much more efficient a description can you get than
> "add N lines, copied lines L, M, add K lines"?  You don't need any
> content in the diff because nothing was deleted.

Yep, like in my above example.

> > > How about just check for a DKIM2 header?  If so memoize the body
> > > verbatim.  If the body was compound, you need to do the regular
> > > processing, and perhaps reject on the basis of "our rules say
> > > mutate but DKIM2 can't deal, so please reformulate your message
> > > to satisfy policy or turn off DKIM2 and we'll do it".  Finally,
> > > MIME-wrap the original body, and compute the change description.
> > > In the cases of text/plain 7bit or 8bit bodies, include a note in
> > > the MIME prelude that "this message body was MIME-wrapped because
> > > the sender uses DKIM2, you need a MIME-capable MUA to view this
> > > as the sender intended."
> > 
> > Works for me.
> 
> Good!  There a couple of other things we can do around the IN queue
> (that means before any real processing, including parsing to an
> email.Message object), such as check size, to avoid some copying.
> 
> > Excellent.  I'm not _as_ experienced with Python as I am with Perl
> > or C, but I've written bits of it (including a chunk of work with
> > offlineimap back in the day).
> 
> You know, if this is "in a year or so DKIM2 is gonna be everywhere"
> priority, there's always Summer of Code 2027.  And don't hesitate to
> ask me/us to do something if you're stuck for time or we seem much
> better able to do it.  We might say "no" (likely, actually, we're
> anything but overstaffed), but we won't get mad.

That's good :). I'll start by reworking to the "MIME-wrap everything".

> > Right now my branches have both an option to turn on dkim2 support
> > entirely, and a per-list switch to control which lists it's enabled
> > for.  I agree that this is the best approach; and I'd strongly
> > agree with defaulting it to being turned off until DKIM2 is fully
> > standardised.
> 
> Great!  We've got a good foundation to start on.
> 
> Ah, disclaimer -- don't expect actual work out of me for a couple
> weeks, as I messed up my back (slipped in dog pee and did a Wyle E
> Coyote style landing on my back, wish I had video!)  Will be OK, but
> there's enough pain still that I shouldn't be driving or coding.
> BS-ing in email is my level.  I can do that (enjoy, in fact). :-)

Oh man!  Ouch.  Sorry to hear that.  I hope you recover well.

BTW, just guessing from the ".jp" address, but I'll be in Tokyo for JPAAWG in 
November, might see you there if you're joining!

Cheers,

Bron.


--
  Bron Gondwana, CEO, Fastmail Pty Ltd / Fastmail US LLC
  [email protected]
_______________________________________________
Mailman-Developers mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/mailman-developers.python.org/
Mailman FAQ: https://wiki.list.org/x/AgA3

Security Policy: https://wiki.list.org/x/QIA9

Reply via email to