Dear Lazyweb,

When Postfix delivers to an unknown user via Dovecot it gets status=deferred but I want a reject in smtpd instead. How fix? mailbox_transport = dovecot:
dovecot unix - n n - - pipe
  flags=DRhu user=vmail:vmail argv=/usr/libexec/dovecot/deliver
  -e -f ${sender} -d ${recipient}

Running deliver by hand shows it exiting with status 75.

Previously, previously, previously.

Tags: , , , , ,

20 Responses:

  1. Frank McConnell says:

    Why is it getting to delivery for an unknown user? Somewhere there should be some sort of map that indicates what localparts are valid in the domain.

    • jwz says:

      Well, as far as I can tell, it attempts delivery of every local user via dovecot (except aliases), and then dovecot rejects the unknown ones.

      • Frank McConnell says:

        I think Postfix needs to be able to tell whether a given localpart is valid when it gets the SMTP RCPT TO: command. That's why I am thinking about maps.

        My involves a bit of legacy (one user with a set of procmailrc files that have been growing for over 20 years) and a bit of new stuff so there's a virtual_alias_domains list and a virtual_mailbox_domains list.

        • Frank McConnell says:

          (whoops, hit return into wrong window)
          So each of those has a maps list too: virtual_alias_maps (which for me maps addresses in virtual alias domains to Unix usernames) and virtual_mailbox_maps (maps addresses in virtual mailbox domains to mailstore subdirectories (in directory named by virtual_mailbox_base)

          Then also I have Dovecot configured with passdb and userdb stanzas that point at a per-domain passwd-format file.

          But I think Postfix is consulting its maps at SMTP RCPT TO: time ("Recipient address rejected: User unknown in virtual alias table" is what I see in the log files for mis-addressed spam.)

          People think sendmail is complicated. Postfix is too, it just uses more long names.

    • jwz says:

      I do have a table in both virtual_mailbox_maps and local_recipient_maps that lists those users who should have local (dovecot) delivery, but that doesn't seem to be being consulted.

      • NB says:

        Does $local_recipient_maps perhaps contain a @domain.tld record that'll tell Postfix to accept anything in the LHS for that domain.tld?

  2. Dovefixer says:

    If you use LMTP to hand off from postfix to Dovecot, then you get what you seek.

    Recommend deleting the dovecot entry from, and change in

    mailbox_transport = lmtp:unix:private/dovecot-lmtp

    Then in dovecot.conf (or conf.d if that's how your system rolls) add this stanza:

    protocol lmtp {
      # Space separated list of plugins to load (default is global mail_plugins).
      #mail_plugins = $mail_plugins
      mail_plugins = $mail_plugins sieve
      postmaster_address =
    • jwz says:

      When I do that I get:
      status=deferred (connect to[private/dovecot-lmtp]: No such file or directory

      Relatedly, for reasons I do not remember or understand, Dovecot is configured with:

        location = maildir:/home/vmail/%n/Maildir:INBOX=/home/vmail/%n/Maildir/.INBOX

      but if Postfix is allowed to write the Maildir files directly, they end up in
      "/home/vmail/%n/Maildir/new/<msgs>" instead of
      "/home/vmail/%n/Maildir/.INBOX/new/<msgs>" and that's... bad? What's the done thing?

    • jwz says:

      Ok, I worked out that I also needed

      service lmtp {
        unix_listener /var/spool/postfix/private/dovecot-lmtp {
          mode  = 0660
          user  = postfix
          group = postfix

      but the switch from pipe to lmtp hasn't really changed anything as I still get a deferral instead of a rejection:

      status=deferred (host[private/dovecot-lmtp] said: 451 4.3.0 <> Internal error occurred

      • Dovefixer says:

        So when I mail to that address my MTA got the rejection from's MTA (redacted):

        <>: host[] said: 550
           5.1.1 <>: Recipient address rejected: User
           unknown in virtual mailbox table Thank you, drive through. (in reply to
           RCPT TO command)
        Reporting-MTA: dns;
        X-Postfix-Queue-ID: 5BE20A7D
        X-Postfix-Sender: rfc822;
        Arrival-Date: Tue, 20 Sep 2022 19:46:07 +0000 (UTC)
        Final-Recipient: rfc822;
        Original-Recipient: rfc822;
        Action: failed
        Status: 5.1.1
        Remote-MTA: dns;
        Diagnostic-Code: smtp; 550 5.1.1 <>: Recipient
           address rejected: User unknown in virtual mailbox table Thank you, drive
  3. cmt says:

    Did you perhaps set soft_bounce in (It defaults to no, which is what you want here, but sometimes in the course of debugging...) But then... "internal error", typically postfix would be rather verbose with that. Is there actually communication happening between postfix lmtp and dovecot?

    • jwz says:

      Did you perhaps set soft_bounce in

      I did not.

      Is there actually communication happening between postfix lmtp and dovecot?

      Mail is actually getting delivered via lmtp, so I'm gonna go with yes? Prior to the "unknown error" response, it did in fact run my "checkpassword" program which exited with 1 for no such user / auth failed.

      Maybe it's because "transport" has an entry for " local:" -- but that seems to be necessary.  Without it, lmtp is not invoked, and Postfix seems to be writing the files directly ("delivered to mailbox") and they are ending up in the wrong inbox (Maildir/new/ instead of Maildir/.INBOX/new/)

      • cmt says:

        That transport entry looks like your postfix is confused about what it should handle.
        My postfix-fu ist somewhat rusty, so proceed with care... But what I remember matches ("Non-Postfix mailbox store). Main takeaways: goes into virtual_mailbox_domains but not (never!) into mydestination, virtual_mailbox_maps lists addresses (don't care for the lookup value), virtual_alias_maps allows aliases (duh) and virtual_transport shoves the mail into the lmtp-client and your dovecot socket. (An older, maybe deprecated method would be to set up mailbox_transport = lmtp:... and ignore the virtual hosting stuff, but that was somewhat dirty even back in the days)

      • tb says:

        If you need the entry in transport, it means that postfix does not recognize as local, and that is why local_recipient_maps is not working.

        In postfix, there are two ways to deliver locally. Either the "classic unix" way, where you put your local domains in mydestination, and the local transport saves mail to mailboxes of local users. Or the newer "virtual" stuff, when you don't want to (or can't) create and manage local users for every mailbox. The important thing is to not mix these two together, or surprising things might happen -  either put a domain in mydestination, and it will use the local stuff, or put it in virtual_mailbox_domains, and it will use the virtual stuff. Never put the same domain in both, and don't try to force local delivery through transport.

        I agree with cmt, that if you deliver directly to dovecot, you should probably use the virtual stuff, it is simpler.

        • jwz says:

          I am using only virtual mail users, not unix users.

          mydestination = localhost, mydomain =, virtual_mailbox_domains = ...etc

          All deliverable aliases are enumerated in $virtual_alias_maps.

          virtual_mailbox_maps contains e.g. " NAME/Maildir/", and that seems to be necessary even though actual delivery is via dovecot-lmtp (it bounces otherwise).

          local_recipient_maps = $alias_maps $virtual_mailbox_maps

          transport_maps contains " local:" and others, and that also seems to be necessary.

          But... I guess things are working now? I don't really understand what changed.

          • tb says:

            If you change

            mailbox_transport = lmtp:unix:private/dovecot-lmtp


            virtual_transport = lmtp:unix:private/dovecot-lmtp

            and remove the " local:" from transport_maps, it should still work ...

            • jwz says:

              Seems to, yes!

              One part that is still puzzling me is that, apparently, the way I indicate "this is the name of a user for whom we accept local delivery" is for that user to have an entry in the $virtual_mailbox_maps file. But only the key seems to matter, not the value -- the Maildir file mentioned there is not used, since dovecot-lmtp decides where the mail goes.

              This makes me wonder if there's any benefit to using dovecot-lmtp and maybe Postfix should just be doing direct delivery into those Maildir files?

              • tb says:

                One reason is that with lmtp you can put postfix and dovecot on separate servers or containers, and they don't need to share a disk. The other is that users might want to filter or sort incoming mail with the sieve plugin in dovecot.

              • K says:

                If you're not doing anything with Dovecot on the ltmp handoff, direct delivery would certainly result in fewer moving parts. It's what I do on the Sisyphean task that is my vanity domain email.