Self-destructing recipient address on Postfix (rewrite recipient address)

I'd like to implement self-destructing e-mail address rules on my Postfix mail server. The idea is to have public address like this:

[email protected]

where 0220 in the address means "February 2020". If Postfix receives e-mail for this address before 3/1/2020 it will be delivered to some non-public e-mail (e.g. [email protected]) but after this date the e-mail is discarded (/dev/null).

Such system would allow me to have infinite number of temporary addresses.

Postfix allows regular expressions to match recipient address but how to do that conditional rewriting based on time?


Make any suitable lookup table dynamic by adding a sufficiently dynamic lookup method, such as SQLite. If postfix itself delivers the mail (no dovecot etc), the alias table seems appropriate. I will demonstrate for local mail (analogous configuration possible for virtual).

You may keep your existing (e.g. hash:) lookup(s) and just add the new method:

alias_maps = hash:/etc/aliases sqlite:/etc/postfix/date-dependant-aliases.cf

You might need to install support for the new lookup type. I chose SQLite, because I do not need to setup a database if my query does not use one.

# /etc/postfix/date-dependant-aliases.cf
dbpath = /dev/null
expansion_limit = 1
query = WITH T (prio, forward_addr, condition) AS ( VALUES (1, '[email protected]', '%s' >= ('john' || substr(strftime('%%Y%%m', 'now'),3))), (2, 'devnull', 1=1)) SELECT forward_addr FROM T WHERE '%s' LIKE 'john____' AND condition ORDER BY prio ASC LIMIT 1;

Explanation of the query (note local delivery agent inserts lowercase key for %s, other % need quoting):

WITH T (prio, forward_addr, condition)                    -- sub-query
AS ( VALUES                                               -- with these 2 rows:
(1, '[email protected]',                              -- 1: real address,
'%s' >= ('john' || substr(strftime('%%Y%%m', 'now'),3))), -- if >= current months alias
    -- SQLite doesnt have 2-digit dates in strftime
(2, 'devnull', 1=1))                                      -- 2: discard, always
SELECT forward_addr FROM T                                -- postfix only needs the target
WHERE '%s' LIKE 'john____'                                -- require matching template
    -- no REGEXP support; just match 4 arbitrary chararacters
AND condition ORDER BY prio ASC LIMIT 1;                  -- select best match from sub-query

You should verify the query suits your needs using postmap:

postmap -q john$(date +'%y%m' -d '+1 year') sqlite:/etc/postfix/date-dependant-aliases.cf
[email protected]
postmap -q john$(date +'%y%m') sqlite:/etc/postfix/date-dependant-aliases.cf
[email protected]
postmap -q john$(date +'%y%m' -d '-31 days') sqlite:/etc/postfix/date-dependant-aliases.cf
devnull
postmap -q john1801 sqlite:/etc/postfix/date-dependant-aliases.cf
devnull

Note the propagate_unmatched_extensions parameter (see man 5 postconf and man 5 aliases), which changes behavior in case of address extensions (+foo) not previously matched.