[pfx] Re: Is virtual_mailbox_maps redundant when virtual_alias_maps already checks mailbox existence

Rajesh Mishra via Postfix-users <[email protected]> Fri, 22 May 2026 14:57:07 +0530
Newsgroups gmane.mail.postfix.user
Message-ID <[email protected]>
Hi,

   Following up on my earlier question. After digging into the Postfix 
source
   and documentation more carefully I believe I have a clearer picture, 
but I
   would like to confirm two candidate configurations before changing 
production.

   --- What I now understand ---

   TCP lookup tables (tcp:) send the full recipient address to the 
daemon exactly
   once. They do not attempt the multi-form lookups (user+ext@domain, 
user@domain,
   @domain) that indexed maps perform. This means my TCP daemon on port 
9926 is
   solely responsible for handling plus-addressing, catchalls, and 
alias-domain
   canonicalisation — Postfix will not retry with a stripped or 
rewritten key.

   Our daemon already does this:
     - Step 1: resolves alias domains in-process (no additional DB 
round-trip)
               and checks for mailbox existence.
     - Step 2: checks for explicit aliases and @domain catchalls.

   So for any recipient in a virtual mailbox domain, by the time
   smtpd_reject_unlisted_recipient would trigger virtual_mailbox_maps, 
our daemon
   has already answered "mailbox does not exist" using the same table 
and the same
   conditions. The virtual_mailbox_maps lookup would always return nothing.

   I also verified that we deliver outbound via SMTP to a relay
   (virtual_transport = smtp:[relay]:587), not via Postfix virtual(8).
   This means virtual_mailbox_maps is consulted only during SMTP-time 
recipient
   validation, not at delivery time for mailbox path resolution. A no-op
   replacement should therefore be safe.

   One thing I want to confirm: setting virtual_mailbox_maps = <empty> while
   keeping smtpd_reject_unlisted_recipient = yes does NOT give us what 
we want —
   it disables the recipient check entirely rather than rejecting 
unknowns. So an
   empty map is not the right answer.

   --- Two candidate designs ---

   Design A — keep virtual_alias_maps for rewriting, replace 
virtual_mailbox_maps
              with a cheap no-op TCP service:

     virtual_alias_maps          = tcp:127.0.0.1:9926
     virtual_mailbox_maps        = tcp:127.0.0.1:9927   # always returns 
NOT_FOUND
     smtpd_reject_unlisted_recipient = yes

     Port 9926 handles both alias rewriting and implicit mailbox validation.
     Port 9927 exists only so Postfix has a non-empty 
virtual_mailbox_maps; it
     returns NOT_FOUND for every query without touching the database.
     smtpd_reject_unlisted_recipient does the rejection.

   Design B — move accept/reject into smtpd_recipient_restrictions, remove
              virtual_mailbox_maps entirely:

     smtpd_reject_unlisted_recipient = no

     smtpd_recipient_restrictions =
         permit_mynetworks
         permit_sasl_authenticated
         reject_unauth_destination
         check_recipient_access tcp:127.0.0.1:9926

     virtual_alias_maps = tcp:127.0.0.1:9927   # alias rewriting only

     Port 9926 speaks access(5) semantics (OK / REJECT / DUNNO) and handles
     accept/reject early at SMTP time. Port 9927 handles alias rewriting at
     cleanup time for messages that were accepted.

   --- Questions ---

   1. For Design A: is there any scenario where Postfix would still consult
      virtual_mailbox_maps for something other than 
smtpd_reject_unlisted_recipient
      validation? For example during cleanup, queue re-injection, or 
virtual(8)
      delivery triggered by some other path?

   2. Are there any other caveats with either design we should be aware of ?

   We are leaning toward Design A as it is the smaller change, but we 
want to
   make sure port 9927 returning NOT_FOUND for every query is genuinely 
safe and
   not just papering over something Postfix legitimately needs.

   Thanks in advance.
   Rajesh Mishra

On 19/05/26 12:23 pm, Rajesh Mishra wrote:
> Hi,
>
>   I want to verify my understanding of the virtual_alias_maps → 
> virtual_mailbox_maps fallback chain before making a configuration 
> change, and also explore whether the chain can be simplified further.
>
>   ---
>   Setup:
>
>   virtual_alias_maps   = tcp:127.0.0.1:9926, 
> proxy:mysql:/etc/postfix/mysql-vam.cf
>   virtual_mailbox_maps = proxy:mysql:/etc/postfix/mysql-vmm.cf
>   smtpd_reject_unlisted_recipient = yes  (default)
>
>   Port 9926 is an in-house TCP lookup daemon. For each RCPT TO it runs 
> two lookups against our database:
>
>   Step 1 — checks whether the mailbox exists for the recipient 
> address, with domain-alias resolution (if the recipient domain is a 
> configured alias, it resolves to the canonical domain before 
> checking). Returns the address if found. For external domains, returns 
> immediately without proceeding to step 2.
>
>   Step 2 — checks for explicit aliases and catchalls for the recipient 
> address.
>
>   If both steps return nothing, port 9926 returns NOT_FOUND. Postfix 
> then tries the MySQL fallback (mysql-vam.cf), which checks the same 
> alias table as step 2. If that also returns nothing, 
> smtpd_reject_unlisted_recipient triggers virtual_mailbox_maps.
>
>   The virtual_mailbox_maps MySQL lookup is a direct mailbox existence 
> check — same table and same status conditions as step 1 above.
>
>   ---
>   Question 1 — Is virtual_mailbox_maps redundant here?
>
>   Since step 1 already checks mailbox existence with identical 
> conditions, by the time virtual_mailbox_maps is reached the same 
> question has already been answered "no" by the same table with the 
> same filters. If the user existed and matched those conditions, step 1 
> would have returned the address, satisfied virtual_alias_maps, and
>   virtual_mailbox_maps would never have been reached.
>
>   We are therefore considering replacing the MySQL 
> virtual_mailbox_maps with a TCP lookup on a separate port that 
> immediately returns NOT_FOUND without hitting the database, on the 
> basis that this check is always a no-op at that point.
>
>   Is our understanding correct? Are there any Postfix-level scenarios 
> — such as lookup caching, address normalisation, or anything in how 
> smtpd_reject_unlisted_recipient interacts with these maps — where 
> virtual_mailbox_maps could legitimately find a recipient that 
> virtual_alias_maps step 1 already missed?
>
>   ---
>   Question 2 — Can virtual_mailbox_maps be skipped entirely?
>
>   Taking this further: is there a way to configure Postfix so that 
> NOT_FOUND from virtual_alias_maps is treated as a rejection directly, 
> without consulting virtual_mailbox_maps at all?
>
>   For example, does setting virtual_mailbox_maps = (empty) while 
> keeping smtpd_reject_unlisted_recipient = yes achieve this? Or does 
> Postfix require a non-empty virtual_mailbox_maps to be able to reject 
> unlisted recipients for virtual mailbox domains?
>
>
> Thanks
> Rajesh Mishra
>
_______________________________________________
Postfix-users mailing list -- [email protected]
To unsubscribe send an email to [email protected]