- Tue 24 October 2023
- Knowledge base
- #mail, #sieve, #filter, #protonmail, #security, #dns, #encryption, #standards, #config
As you could learn from the "sunsetting" blog post, I am exploring the depths of email as a service (a whole new concept to me) in the form of ProtonMail. During this surveying period, I found some limits that need some non-evident fiddling to overcome.
Filters that work on email headers
Sometimes you want to label or move emails depending on presence, absence or comparison of a specific message header. This is not possible in the ProtonMail filter wizard, as this one only works on subject, sender, recipient or attachments. Custom Sieve filters to the rescue! You simply need to ensure to manually create labels or folders referenced in Sieve filters.
Label potentially spammy messages
Useful to heighten your senses to detect baddies.
require ["include", "environment", "variables", "relational", "comparator-i;ascii-numeric", "spamtest"];
require "fileinto";
# Generated: Do not run this script on spam messages
if allof (environment :matches "vnd.proton.spam-threshold" "*",
spamtest :value "ge" :comparator "i;ascii-numeric" "${1}")
{
return;
}
if header :value "gt" :comparator "i;ascii-numeric" "X-Pm-Spamscore" "2" {
fileinto "spammy";
}
Another option is to rely on the spamtest
extension. It's just
that you have no insight there. With my above solution, you can adjust labelling
by aligning to the X-Pm-Spamscore
message header.
fileinto
works for folders and labels
fileinto "<foo>"
references either a folder or a label. So if you created
a folder, it will move it there. If you created a label, the email will get
that label applied.
Label mails coming from SimpleLogin
require "fileinto";
# Label all mails forwarded by SimpleLogin
# WARNING: if you attach PGP public keys automatically (see settings),
# the "hidden" original mail address will be leaked on reply
if header :is "X-Simplelogin-Type" "Forward" {
fileinto "simplelogin";
}
Move emails collected by a catch-all address to a folder
As these are very likely to be spam anyways, you might want to have them out of your way.
require "fileinto";
# Label all external mails
if header :is "Delivered-To" "<catchall>@<example.org>" {
fileinto "harvester";
}
Label emails not sent from ProtonMail
This adds a label to email received from the outsideā¢.
require ["include", "environment", "variables", "relational", "comparator-i;ascii-numeric", "spamtest"];
require "fileinto";
# Generated: Do not run this script on spam messages
if allof (environment :matches "vnd.proton.spam-threshold" "*",
spamtest :value "ge" :comparator "i;ascii-numeric" "${1}")
{
return;
}
# Label all external mails
if header :is "X-Pm-Origin" "external" {
fileinto "external";
}
Label emails received without transport encryption
Today this is already a sign of poor craftsmanship and increased risk of spam or scam.
require ["include", "environment", "variables", "relational", "comparator-i;ascii-numeric", "spamtest"];
require "fileinto";
# Generated: Do not run this script on spam messages
if allof (environment :matches "vnd.proton.spam-threshold" "*",
spamtest :value "ge" :comparator "i;ascii-numeric" "${1}")
{
return;
}
# Label all mails that have been sent without transport encryption (TLS)
if header :is "x-pm-transfer-encryption" "none" {
fileinto "unencrypted";
}
MTA-STS with a custom domain
On a paid plan, you can use your own domain to send/receive mail. People have already written down everything worth knowing about MTA-STS. But I need to document my own set-up somewhere and eventually somebody can profit from this.
Web part (mta-sts.txt)
Create a text file reachable at https://mta-sts.example.org/.well-known/mta-sts.txt
and adjust
mode
and max_age
to your needs:
version: STSv1
mode: testing
mx: mail.protonmail.ch
mx: mailsec.protonmail.ch
max_age: 604800
See RFC 8461 for details on the supported modes and max_age configuration.
MTA-STS requirements
MTA-STS policies are obviously fetched via HTTPS only so ensure you have a valid certificate. Additionally:
- return the text file as
text/plain
- ensure to not cache it
- respond with
HTTP 200
(redirects are not followed)
More details in https://datatracker.ietf.org/doc/html/rfc8461#section-3.3
DNS records
- Depending on your DNS/web server setup: create the necessary DNS record to support serving the above text file to MTAs
-
Create an additional DNS TXT record like this (the
id
value needs to uniquely identify a version of the policy, so use a method to represent a point in time (e.g. UNIX timestamp or ISO 8601 dates)_mta-sts.example.org. 120 IN TXT "v=STSv1; id=1696855385"
-
Whenever you make textual changes in
mta-sts.txt
, update theid
value of the TXT record afterwards