For some reason, I was a user of EnigMail (ThunderBird). However, the other day, I decided to make a decrypted copy of PGP encrypted mail in bulk. Single decryption can be done by right-clicking on the email and selecting "Decrypt to folder", but batch decryption must be done by using the email filter "If OpenPGP encrypted, create decrypted copy". But for some reason the filter didn't work in my environment. By the way, I found a minor problem in decoding by right-clicking, so I tried to fix it. That is https://gitlab.com/enigmail/enigmail/-/merge_requests/47. In the process, I was investigating https://gitlab.com/enigmail/enigmail/blob/enigmail-2.1-branch/package/persistentCrypto.jsm, but I thought that the decryption process would be easy, so I implemented it. I tried.
I chose Python because it's the language I've been most familiar with these days, and the mail parser is in the standard library.
IMAP
EnigMail is an extension of ThunderBird, but IMAP access is required because this tool works standalone. This can be a copy of https://docs.python.org/ja/3/library/imaplib.html#imap4-example almost entirely.
GnuPG was used as the de facto standard. Since GnuPG is an external program, it requires a subprocess module. However, subprocess.Popen does not have a context manager. So I created a Popen wrapper that would stop the process if an exception occurred during the (code) block.
You can send the text to gpg --decrypt --skip-verify
(--skip-verify is required because you want it to be decrypted regardless of the verification result). For multi-parts, one part at a time. However, if Content-Transfer-Encoding is specified, it needs to be processed in advance. Use base64.b64 decode or quopri.decode string.
If the content is encoded from the beginning (or if it contains multibyte characters), it needs to be encoded. This encoding is an implementation that breaks Base64 every 72 characters, following EnigMail, but it is necessary to break even if only the end is less than 72 characters (A).
Although the file name of the attached file is taken out, PGP seems to have a function to embed the file name in the encrypted file (?). GnuPG is an option called --enable-special-filenames
, and filenames called-& N
may be embedded, so if a filename in this format comes in, it should be ignored (B). However, the tool created this time does not have this effect because it always uses the Content-Disposition filename instead of the embedded file name.
Note that (A) and (B) are the contents of EnigMail's "minor defects".
PGP/MIME
The first of the MIME parts is version information (always 1), and the second is real mail (but not including headers). Therefore, the header may be copied and returned to the "entity mail".
PGP / MIME wrote that the body mail does not include a header, but EnigMail subject encryption is implemented by entering the subject header in the body mail. Therefore, when copying the header to the actual mail, it is sufficient not to copy the header that already exists.
With https://github.com/cielavenir/imap_mass_decrypter/blob/master/imap_decrypter.py, I was able to successfully batch decrypt (I don't use pypi). Moreover, the mail filter needs to specify the folders to be filtered one by one, but here you can target all folders at once.