2021-02-22
The mhbuild
directives I want for sending MIME attachments with MH
I use and like (N)MH for any number
of reasons (it's a very Unix and command line focused mail system,
although I often use it with exmh).
However, for my sins I sometimes have to send people email with
(MIME) attachments of things like PDFs and images, especially these
days when I can't just give them physical printouts. This is possible
in NMH, but the manual page for mhbuild
, the
core program you need to do this, is both relatively opaque and
full of discussions about things that I mostly don't care about.
Since I always wind up picking painfully through the mhbuild
manpage when I need it, today I'm going to write down the magic
directives you (I) need and also the simpler way that I discovered
while writing this entry.
Suppose that we start with a FILE.PDF that we want to send. Our end goal is to wind up with an attachment that as at least the following MIME headers:
Content-Type: application/pdf; name="FILE.PDF" Content-Disposition: attachment; filename="FILE.PDF" Content-Transfer-Encoding: base64
In theory the 'name="..."' on the Content-Type is unnecessary and only
exists for historical reasons.
In practice, it's common practice in MIME messages to put the filename
in both places. You can also have a Content-Description
, and
optionally a Content-ID
, which I think is generally irrelevant for
attachments.
The simple and often sufficient way to add one or more attachments
to your message is to list them as Attach
headers in your draft
(and then use the 'mime
' command in whatnow
to
activate all of mhbuild's processing). The format of these is simply:
Attach: /path/to/some/FILE.PDF
If NMH can get the MIME type right, this will do just what you want
(including providing a Content-Description that's the base filename
without its directory). Even if it gets the MIME type wrong, you
can fix that by editing the Content-Type:
by hand afterward, and
for that matter you can edit the file name (in all its places) if
you would like your recipient to see a different file name than you
have locally. In a lot of cases I think this will be good enough
for what I want to attach, especially if I rename my PDFs before
hand.
(I didn't discover about Attach
until now for many reasons, including
that the mhbuild
manpage doesn't exactly encourage extensively and
carefully reading of all of it. It's very MH manpage-y, for better or
worse.)
The more complex way is to use a mhbuild directive to specify everything you want. The mhbuild manpage has a lot to say about directives, but much of it is for complicated and odd cases that I don't care about. The format we want for attaching files is:
#application/pdf; name="FILE.PDF" <> {attachment; filename="FILE.PDF"} /path/argle.pdf
(Notice that this example renames the PDF; it is argle.pdf on the filesystem, but the recipient will see it called FILE.PDF.)
For my future reference, this directive breaks down as follows. The
first part becomes the Content-Type. The <>
tells mhbuild to not
generate a Content-ID, which is generally surplus. The {...}
becomes the Content-Disposition. We're specifying the filename MIME
parameter here, but you can leave it out if you're happy with the
recipient seeing your local file name (this is the same as with
Attach
). If you leave out the '{ ... }
' portion entirely, the
result will have no Content-Disposition header.
If you want to go the extra distance you can also also provide a
Content-Description by using [...], square brackets, as in '[Amazon
purchase invoice #10]
'. This goes after the <> and before the {...}
(or before the filename, if you leave out the {...}). I don't know
how many mail clients show or care about the Content-Description;
it's not all that common in my saved mail, and most of the time
it's just another copy of the file name.
Given all of this, the minimal version is:
#application/pdf <> {attachment} /path/to/FILE.PDF
This will have no 'name=' parameter on the Content-Type, but will have a
'filename=' parameter on the Content-Disposition so the recipient's mail
client will probably let them save it under some useful name. If you're
not sure what MIME type some file should be, you can use 'file --mime
'
to see what it thinks or default to application/octet-stream
. If you
do the latter, you'll be in good company; we see plenty of attachments
on incoming legitimate email that have been defaulted that way even when
there are more applicable MIME types.
How I set up testing alerts in our Prometheus environment
One of the things I mentioned in my entry on how our alerts are quiet most of the time is that I have some Prometheus infrastructure for 'testing' alerts. Rather than being routed to everyone (via the normal email destination), these alerts go to a special destination that only goes to interested parties (ie, me). There are a number of different ways to implement this in Prometheus, so the way I picked to do it isn't necessarily the best one (and in fact it enables a bad habit, which is for another entry).
The simplest way to implement testing alerts is to set them up purely in Alertmanager. As part of your Alertmanager routing configuration, you would have a very early rule that simply listed all of the alerts that are in testing and diverted them. This would look something like this:
- match_re: alertname: 'OneAlert|DubiousAlert|MaybeAlert' receiver: testing-email [any other necessary parameters]
The problem with this is that it involves more work when you set up a new testing alert. You have to set up the alert itself in your Prometheus alert rules, and then you have to remember to go off to Alertmanager and update the big list of testing alerts. If you forget or make a typo, your testing alerts go to your normal alert receivers and annoy your co-workers. I'm a lazy person, so I picked a more general approach.
My implementation is that all testing alerts have a special Prometheus label with a special value, and then the Alertmanager matches on the presence of this (Prometheus) label. In Alertmanager this looks like:
- match: send: testing receiver: testing-email
Then in each Prometheus alert rule, we explicitly add the label and the label value in each testing rule:
- alert: MaybeAlert expr: .... labels: [...] send: testing annotations: [...]
(We add some other labels for each alert, to tell us things such as whether the alert is a host-specific one or some other type of alert, like a machine room being too hot.)
This enables my laziness, because I only need to edit one file to create a new testing alert instead of two of them, and there's a lower chance of typos and omissions. It also has the bonus of keeping the testing status of an alert visible in the alert rule file, at the expense of making it harder to get a list of all alerts that are in testing. For me this is probably a net win, because I look at alert rules more often than I look at our Alertmanager configuration so I have a higher chance of seeing a still-in-testing rule in passing and deciding to promote it to production. And if I'm considering promoting a testing alert to full production status, I can re-read the entire alert in one spot while I'm thinking about it.
(Noisy testing rules get removed rapidly, but quiet testing rules can just sit there with me forgetting about them.)