Last active
January 9, 2025 18:29
-
-
Save thedaveCA/2a4f254ba1d2a7ee658d1864c5d4feb5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
### Label messages with ${domain}.${mailbox} | |
# | |
# This is overkill, but read the preamble and then look for the "configuration" | |
# | |
### PREAMBLE | |
# | |
# Fastmail uses . as a folder separator, and ^ as a literal dot. Ugh. | |
# | |
# X-Delivered-To header is used to determine the actual destination of the | |
# message after alias processing. If you wanted the raw RCPT TO, try: | |
# if envelope :regex "to" ... | |
# | |
# Since there is no loop construct, we repeat the replacement until we get | |
# bored, then truncate the string with ... (^^^), which is unlikely to occur | |
# | |
# Note that Fastmail roots your mailbox at "INBOX.", therefore the initial | |
# "INBOX." is effectively discarded (from the perspective of the web client). | |
# tl;dr: If you want a label "example.com" under your inbox, use "INBOX.INBOX." | |
# | |
# Fastmail creates mailbox.domain and *@mailbox.domain addresses automatically, | |
# subdomains are handled as follows: | |
# [email protected] -> example.com\dave | |
# [email protected] -> example.com\dave\test | |
# | |
# @fastmail.co.uk would be parsed asthough it were [email protected] therefore | |
# we check for the suffixes we use and adjust the regex accordingly. | |
# I have no intention of stress-testing Fastmail's sieve implementation by | |
# importing the entire public suffix list, so you'll have to add your own. | |
# co.uk and com.au are listed as examples. | |
# | |
### CONFIGURATION | |
# Set to INBOX. to file labels under the inbox, or "" to file at the root. | |
# Must end with a dot (.) or be completely blank. | |
set "labelprefix" "INBOX."; | |
# Set to true to create parent labels, e.g. | |
# [email protected] -> example.com, example.com\dave, example.com\dave\test | |
# | |
# Set to false to only create the most specific label, e.g. | |
# example.com\dave\test | |
set "parentlabels" "true"; | |
# List your suffixes here, separated by pipes (|) and escaped dots (\\.) | |
set "subdomainsplitter" ".*(co\\.uk|com\\.au)$"; | |
### END OF CONFIGURATION | |
# This is a bit of a hack for when the root domain contains 2 dots. | |
if header :regex "X-Delivered-to" "${subdomainsplitter}" { | |
set "subdomainsplitter" "^(.*)@([^.]*)\\.(.*\\..*\\..*)$"; | |
} else { | |
set "subdomainsplitter" "^(.*)@([^.]*)\\.(.*\\..*)$"; | |
} | |
# Handle MailFetch, based on no X-Delivered-To and a X-LinkName+X-LinkId | |
if allof (not exists ["X-Delivered-To"], | |
header :value "ge" :comparator "i;ascii-numeric" ["X-LinkId"] ["0"], | |
header :regex "X-LinkName" "(.*@.*)") { | |
addheader "X-Delivered-To" "${1}"; | |
} | |
# Extract the mailbox, subdomain(?), and rootdomain from the header | |
if header :regex "X-Delivered-To" "${subdomainsplitter}" { | |
set :lower "mailbox" "${1}"; | |
set :lower "subdomain" "${2}"; | |
set :lower "rootdomain" "${3}"; | |
set "subdomainexists" "true"; | |
} elsif header :regex "X-Delivered-To" "^(.*)@(.*)$" { | |
set :lower "mailbox" "${1}"; | |
set :lower "rootdomain" "${2}"; | |
} | |
# Replace each dot (.) with a caret (^) in rootdomain | |
if string :regex "${rootdomain}" "^([^.]*)\\.(.*)$" { set "rootdomain" "${1}^${2}"; | |
if string :regex "${rootdomain}" "^([^.]*)\\.(.*)$" { set "rootdomain" "${1}^${2}"; | |
if string :regex "${rootdomain}" "^([^.]*)\\.(.*)$" { set "rootdomain" "${1}^${2}"; | |
if string :regex "${rootdomain}" "^([^.]*)\\.(.*)$" { set "rootdomain" "${1}^${2}"; | |
if string :regex "${rootdomain}" "^([^.]*)\\.(.*)$" { set "rootdomain" "${1}^${2}"; | |
if string :regex "${rootdomain}" "^([^.]*)\\.(.*)$" { set "rootdomain" "${1}^^^"; | |
}}}}}} # I'm so sorry | |
# Replace each dot (.) with a caret (^) in mailbox | |
if string :regex "${mailbox}" "^([^.]*)\\.(.*)$" { set "mailbox" "${1}^${2}"; | |
if string :regex "${mailbox}" "^([^.]*)\\.(.*)$" { set "mailbox" "${1}^${2}"; | |
if string :regex "${mailbox}" "^([^.]*)\\.(.*)$" { set "mailbox" "${1}^${2}"; | |
if string :regex "${mailbox}" "^([^.]*)\\.(.*)$" { set "mailbox" "${1}^${2}"; | |
if string :regex "${mailbox}" "^([^.]*)\\.(.*)$" { set "mailbox" "${1}^${2}"; | |
if string :regex "${mailbox}" "^([^.]*)\\.(.*)$" { set "mailbox" "${1}^^^"; | |
}}}}}} # It isn't my fault, there are no loops in Sieve | |
# Finally, file the message into the appropriate folder. | |
if string :is "${subdomainexists}" "true" { | |
if string :is "${parentlabels}" "true" { | |
fileinto :copy :create "INBOX.${labelprefix}${rootdomain}"; | |
fileinto :copy :create "INBOX.${labelprefix}${rootdomain}.${subdomain}"; | |
} | |
fileinto :copy :create "INBOX.${labelprefix}${rootdomain}.${subdomain}.${mailbox}"; | |
} else { | |
if string :is "${parentlabels}" "true" { | |
fileinto :copy :create "INBOX.${labelprefix}${rootdomain}"; | |
} | |
fileinto :copy :create "INBOX.${labelprefix}${rootdomain}.${mailbox}"; | |
} | |
if header :matches "Subject" "SIEVE Test*" | |
{ | |
addheader "X-SIEVE-TROUBLESHOOTING" "labelprefix: ${labelprefix} rootdomain: ${rootdomain} subdomain: ${subdomain} mailbox: ${mailbox}"; | |
set "hasmailbox" "Y"; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment