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:


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. mark@mydomain.com) 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?

  • 1
    I'm interested if that that can be done native in Postfix. In the past I have used the recipient_delimiter + sub-addressing separator which allows you to use any sub-address label after your local username username+label@example.com and the power of procmail (or other mail filters such as sieve ) to accept, discard and store "unique" email addresses in separate folders without having to set up specific aliases before hand.
    – HBruijn
    Oct 7 '19 at 11:05

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, 'mark@mydomain.example', '%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, 'mark@mydomain.example',                              -- 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
postmap -q john$(date +'%y%m') sqlite:/etc/postfix/date-dependant-aliases.cf
postmap -q john$(date +'%y%m' -d '-31 days') sqlite:/etc/postfix/date-dependant-aliases.cf
postmap -q john1801 sqlite:/etc/postfix/date-dependant-aliases.cf

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.

  • Your reply inspired me to try different "sufficiently dynamic lookup method": tcp map as described here postfix.org/tcp_table.5.html. But I've run into some security constrains (error: tcp:localhost:4444 map is not allowed for security sensitive data)
    – bizwiz
    Oct 9 '19 at 6:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.