VIRTUAL(5)
π VIRTUAL(5) β File Formats Manual π
okay bestie, sit down, hydrate, and let me tell you about virtual β the Postfix virtual alias table format. this is VIRTUAL(5) and it's about to be your new hyperfixation, no cap. π¦
β¨ NAME β¨
virtual β the Postfix virtual alias table format π
πΈ SYNOPSIS πΈ
postmap /etc/postfix/virtual
postmap -q "string" /etc/postfix/virtual
postmap -q - /etc/postfix/virtual <inputfile
π DESCRIPTION π
so. the optional virtual(5) alias table (virtual_alias_maps) applies to all recipients: local(8), virtual, and remote. it's giving equal opportunity. this feature is implemented in the Postfix cleanup(8) daemon before mail is queued β so it happens early, bestie, it's the main character of the queueing process. these tables are often queried with a full email address (like, including the domain, the whole thing).
this is not like the aliases(5) table (alias_maps), which only applies to local(8) recipients. that table only ever gets queried with the email address localpart (no domain, just the vibe, not the whole address).
virtual aliasing is recursive β like, it can loop back on itself. to terminate recursion for a specific address, you alias that address to itself. yes, it's a "touch grass" move for your mail server. π
the main applications of virtual aliasing are:
- to redirect mail for one address to one or more addresses.
- to implement virtual alias domains where all addresses are aliased to addresses in other domains.
virtual alias domains are not to be confused with the virtual mailbox domains that are implemented with the Postfix virtual(8) mail delivery agent. with virtual mailbox domains, each recipient address can have its own mailbox. different thing, bestie, don't mix them up. π
virtual aliasing is applied only to recipient envelope addresses, and does not affect message headers. use canonical(5) mapping to rewrite header and envelope addresses in general β that's the one for the whole shebang.
normally, the virtual(5) alias table is specified as a text file that serves as input to the postmap(1) command to create an indexed file for fast lookup. glow up via indexing. β¨
run the command postmap /etc/postfix/virtual to rebuild a default-type indexed file after changing the text file, or run postmap type:/etc/postfix/virtual to specify an explicit type.
the default indexed file type is configured with the default_database_type parameter. depending on the platform this may be one of lmdb:, cdb:, hash:, or dbm: (without the trailing ':').
when the table is provided via other means such as NIS, LDAP or SQL, the same lookups are done as for ordinary indexed files. managing such databases is outside the scope of Postfix β that's on you, bestie, not Postfix's problem. π
alternatively, the table can be provided as a regular-expression map where patterns are given as regular expressions, or lookups can be directed to a TCP-based server. in those case, the lookups are done in a slightly different way as described below under "REGULAR EXPRESSION TABLES" or "TCP-BASED TABLES".
π CASE FOLDING π
the search string is folded to lowercase before database lookup β so like, it goes lowercase before anyone sees it. as of Postfix 2.3, the search string is not case folded with database types such as regexp: or pcre: whose lookup fields can match both upper and lower case. those ones are case-sensitive and they know it. π
π TABLE FORMAT π
the input format for the postmap(1) command is as follows:
pattern address, address, ...β whenpatternmatches a mail address, replace it by the corresponding address.- blank lines and comments β empty lines and whitespace-only lines are ignored, as are lines whose first non-whitespace character is a
'#'. so go ahead, annotate your life. βοΈ - multi-line text β a logical line starts with non-whitespace text. a line that starts with whitespace continues a logical line. (yes, whitespace is load-bearing here.)
π₯ TABLE SEARCH ORDER π₯
with lookups from indexed files such as DB or DBM, or from networked tables such as NIS, LDAP or SQL, each user@domain query produces a sequence of query patterns as described below.
each query pattern is sent to each specified lookup table before trying the next query pattern, until a match is found. it's a whole search journey and it doesn't stop until it finds the one. π
user@domain address, address, ...β redirect mail foruser@domaintoaddress. this form has the highest precedence. it's the VIP, the front of the line. πuser address, address, ...β redirect mail foruser@sitetoaddresswhensiteis equal to$myorigin, whensiteis listed in$mydestination, or when it is listed in$inet_interfacesor$proxy_interfaces.
this functionality overlaps with the functionality of the local aliases(5) database. the difference is that virtual(5) mapping can be applied to non-local addresses. so it's the same energy but broader reach. π
@domain address, address, ...β redirect mail for other users indomaintoaddress. this form has the lowest precedence.
Note:@domainis a wild-card. with this form, the Postfix SMTP server accepts mail for any recipient indomain, regardless of whether that recipient exists. this may turn your mail system into a backscatter source: Postfix first accepts mail for non-existent recipients and then tries to return that mail as"undeliverable"to the often forged sender address. it's giving messy. π
to avoid backscatter with mail for a wild-card domain, replace the wild-card mapping with explicit 1:1 mappings, or add a reject_unverified_recipient restriction for that domain:
smtpd_recipient_restrictions =
...
reject_unauth_destination
check_recipient_access
inline:{example.com=reject_unverified_recipient}
unverified_recipient_reject_code = 550
in the above example, Postfix may contact a remote server if the recipient is aliased to a remote address. π«Ά
π RESULT ADDRESS REWRITING π
the lookup result is subject to address rewriting:
- when the result has the form
@otherdomain, the result becomes the same user inotherdomain. this works only for the first address in a multi-address lookup result. (first come, first rewritten.) - when
"append_at_myorigin=yes", append"@$myorigin"to addresses without"@domain". - when
"append_dot_mydomain=yes", append".$mydomain"to addresses without".domain".
π¦ ADDRESS EXTENSION π¦
when a mail address localpart contains the optional recipient delimiter (e.g., user+foo@domain), the lookup order becomes: user+foo@domain, user@domain, user+foo, user, and @domain. that's five (5) whole tries, she's thorough. π
the propagate_unmatched_extensions parameter controls whether an unmatched address extension (+foo) is propagated to the result of a table lookup.
π VIRTUAL ALIAS DOMAINS π
besides virtual aliases, the virtual alias table can also be used to implement virtual alias domains. with a virtual alias domain, all recipient addresses are aliased to addresses in other domains.
virtual alias domains are not to be confused with the virtual mailbox domains that are implemented with the Postfix virtual(8) mail delivery agent. with virtual mailbox domains, each recipient address can have its own mailbox. (saying it twice because it matters, bestie. β)
with a virtual alias domain, the virtual domain has its own user name space. local (i.e. non-virtual) usernames are not visible in a virtual alias domain. in particular, local aliases(5) and local mailing lists are not visible as localname@virtual-alias.domain. it's a whole separate universe. π
support for a virtual alias domain looks like:
/etc/postfix/main.cf:
virtual_alias_maps = hash:/etc/postfix/virtual
Note: some systems usedbmdatabases instead ofhash. see the output from"postconf -m"for available database types.
/etc/postfix/virtual:
virtual-alias.domain anything (right-hand content does not matter)
postmaster@virtual-alias.domain postmaster
user1@virtual-alias.domain address1
user2@virtual-alias.domain address2, address3
the virtual-alias.domain anything entry is required for a virtual alias domain. without this entry, mail is rejected with "relay access denied", or bounces with "mail loops back to myself". so like, don't skip it, it's the entry that holds the whole domain together. π«
do not specify virtual alias domain names in the main.cf mydestination or relay_domains configuration parameters. just don't, it causes chaos.
with a virtual alias domain, the Postfix SMTP server accepts mail for known-user@virtual-alias.domain, and rejects mail for unknown-user@virtual-alias.domain as undeliverable.
instead of specifying the virtual alias domain name via the virtual_alias_maps table, you may also specify it via the main.cf virtual_alias_domains configuration parameter. this latter parameter uses the same syntax as the main.cf mydestination configuration parameter.
πΈ REGULAR EXPRESSION TABLES πΈ
this section describes how the table lookups change when the table is given in the form of regular expressions. for a description of regular expression lookup table syntax, see regexp_table(5) or pcre_table(5).
each pattern is a regular expression that is applied to the entire address being looked up. thus, user@domain mail addresses are not broken up into their user and @domain constituent parts, nor is user+foo broken up into user and foo. no splitting, no slicing, the whole address or nothing. π―
patterns are applied in the order as specified in the table, until a pattern is found that matches the search string.
results are the same as with indexed file lookups, with the additional feature that parenthesized substrings from the pattern can be interpolated as $1, $2 and so on. cute little capture groups, we love to see it. π
π TCP-BASED TABLES π
this section describes how the table lookups change when lookups are directed to a TCP-based server. for a description of the TCP client/server lookup protocol, see tcp_table(5). this feature is available in Postfix 2.5 and later.
each lookup operation uses the entire address once. thus, user@domain mail addresses are not broken up into their user and @domain constituent parts, nor is user+foo broken up into user and foo.
results are the same as with indexed file lookups.
π BUGS π
the table format does not understand quoting conventions. that's it, that's the bug. quotes mean nothing here, bestie. π
(part 2 incoming, don't go anywhere bb π«Ά)
πΈ CONFIGURATION PARAMETERS πΈ
okay bestie, these are the main.cf parameters that are especially relevant to this whole topic, and they are lowkey the whole plot β¨ The Postfix main.cf file has all the syntax details and the default values, so go read it there. And listen β run the postfix reload command after you change a configuration. no cap, don't skip it π
virtual_alias_maps($virtual_maps) β optional lookup tables that usually get searched with a full email address (domain and all π), and that apply to every recipient out there:local(8), virtual, and remote. This is not howalias_mapsmoves β those only get searched with a localpart (no domain) and only apply tolocal(8)recipients. different vibe entirely, fr fr.virtual_alias_domains($virtual_alias_maps) β Postfix is the final destination for whatever list of virtual alias domains you drop here, meaning domains where every single address is aliased to addresses in other local or remote domains. it's giving "everything gets forwarded, we don't live here" π¦propagate_unmatched_extensions(canonical,virtual) β which address lookup tables copy an address extension from the lookup key over to the lookup result. inheritance, but make it address extensions π
π«Ά Other parameters of interest:
inet_interfaces(all) β the local network interface addresses that this mail system receives mail on.mydestination($myhostname,localhost.$mydomain,localhost) β the list of domains that are delivered via the$local_transportmail delivery transport. the local delivery guest list πmyorigin($myhostname) β the domain name that locally-posted mail appears to come from, and that locally posted mail is delivered to. main character origin story πowner_request_special(yes) β enables special treatment forowner-listnameentries in thealiases(5)file, and stops it from splitting theowner-listnameandlistname-requestaddress localparts when therecipient_delimiteris set to"-".proxy_interfaces(empty) β the remote network interface addresses that this mail system receives mail on by way of a proxy or network address translation unit.
β¨ SEE ALSO β¨
cleanup(8), canonicalize and enqueue mailpostmap(1), Postfix lookup table managerpostconf(5), configuration parameterscanonical(5), canonical address mapping
π README FILES π
use postconf readme_directory or postconf html_directory to go find where all this info is hiding, bestie π
ADDRESS_REWRITING_README, address rewriting guideDATABASE_README, Postfix lookup table overviewVIRTUAL_README, domain hosting guide
π LICENSE π
The Secure Mailer license must be distributed with this software. periodt. that's the whole rule π«‘
π AUTHOR(S) π
Wietse Venema IBM T.J. Watson Research P.O. Box 704 Yorktown Heights, NY 10598, USA
Wietse Venema Google, Inc. 111 8th Avenue New York, NY 10011, USA
π annnnd that's the whole page, bestie! This was VIRTUAL(5) β section 5 of the manual, with its source/version stamp and date sitting right there in the footer at the bottom of the page β so go forth and alias responsibly, you absolute icon π β¨π¦
π¦ where this page comes from
- alpine 3.24: postfix-doc 3.11.7-r0 Β· IPL-1.0 EPL-2.0
- arch rolling: postfix 3.11.7-1 Β· EPL-2.0 OR IPL-1.0 AND BSD-4-Clause-UC
- nixos 26.05: postfix 3.11.7
- nixpkgs unstable: postfix 3.11.7
- ubuntu stonking: postfix 3.11.7-1ubuntu2
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms