Sensible Git mail for the occasional user

Tuesday, 11 Mar 2014

This entry is mostly for my own benefit, since – being an occasional user – I keep having to figure this out from scratch. What I was aiming for is a workflow that gives me both convenience and full control.

I don’t like git send-email. The command assembles and sends mail all in one go, so you have to know what it will do blindly. Running git format-patch manually first only helps a little, since git send-email still performs its own mail assembly on top of its input. It needs practice – using it frequently for a while and looking at the results. I don’t use it enough for that.

Unfortunately the patchmail I do send every once in a while goes to places with many subscribers, and I’m unwilling to rattle their inboxes with my (repeat!) learning process. I want to be sure I’ll send exactly the mail I mean to, on the very first try. Of course I could dry-run my patchmails by sending them to myself first – fiddly and always one command line typo away from making any mistake public.

I also have msmtp set up on my home server with all the details of my SMTP accounts and really don’t want to maintain another copy of that information on my laptop, especially on a per-repository basis.

So for me, the answer is to avoid git send-email entirely.

The key realisation is that once a mail is properly formatted, sending it is nothing more than piping it to /usr/bin/sendmail (or whatever equivalent you employ) – so you actually need only git format-patch.

There is just one little wrinkle to take care of: git format-patch produces output that cannot be piped to sendmail verbatim, because it starts with a “From ” line. This is easily removed using formail, which can also split mboxes – a natural companion to git format-patch --stdout. Bottom line:

git format-patch --to devs@example.net --stdout origin | formail -I 'From ' -s sendmail -t

Here, git format-patch produces an mbox-format mail folder. (Season that to taste with the --to/--cc/etc. switches you require.) This is processed using formail, which splits it into individual mails and pipes them individually to sendmail (“-s sendmail -t”) after deleting the From line (“-I 'From '”).

This essentially replicates git send-email – but note what I gained here:

I can omit the pipe to formail.

If I just call git format-patch by itself, I can inspect the exact mail that will be sent. In fact, if you don’t pipe the output anywhere, Git will invoke the pager for you and even highlight the diffs within the attachments: excellent. Very convenient for careful reading.

Then if I’m satisfied, I add the pipe and out go the patches.

I know exactly what is being mailed out. There is no blackbox. This is much like sending a dry-run to myself first, then sending for real, except with all the friction removed.

And if there was a cover letter I needed to edit? Then I just pipe to a file first, before piping to formail. In between those steps, I can edit the file – whether in Vim directly, or using mutt -f mbox.

Of course, this isn’t necessarily for everyone. You need a machine with procmail installed (to get formail) and a sendmail-compatible MTA set up. You also need to be comfortable working with mail in the raw. There is, after all, no blackbox.

But it works for me. Sending patchmail is no longer something I put off.