Hi Martijn,

Thanks for the detailed solution!

I eventually solved my problem another way: I kept all dovecot virtual
users under a single system user 'vmail', and I made Dovecot handle
virtual address aliasing, i.e., Dovecot's LMTP accepts either virtual
users or virtual aliases as the RCPT TO: recipient, and deliver in the
actual Maildir.

My smtpd.conf now looks like

-----------------------
table virtual-users sqlite:/etc/smtpd-sqlite.conf

action "lmtp_dovecot" lmtp "/run/dovecot/lmtp" rcpt-to user "vmail"
userbase <virtual-users>

match for rcpt-to <virtual-users> action "lmtp_dovecot"
-----------------------

The `user "vmail"` clause on the "action" line prevents OpenSMTPd from
querying userinfo at all, and the `rcpt-to <virtual-users>` in the
match clause ensures that only those virtual users (or aliases) known
by Dovecot will match (as opposed to the previous `for domain <virtual-
users>` clause, which would match any address, known or otherwise, in a
domain known to Dovecot).

(note: system users and system aliases are handled by a different part
of the OpenSMTPd config.)

Regards,
Albert.

Le dimanche 14 décembre 2025 à 12:00 +0100, Martijn van Duren a écrit :
> Hello Albert,
> 
> My personal solution to this is to replace the '@' sign with an
> underscore for the parts where a local user is needed. So via
> query_alias I would map [email protected] to albert_aribaud.net.
> From there the query_userinfo would take over and look for
> albert_aribaud.net.
> 
> Since the underscore is not a valid hostname character there's no
> risk here. The specific queries need to be tailored to your database
> situation (or the other way around). But my queries (which I wrote
> over 10 years ago) look like this:
> query_alias SELECT recipient FROM alias WHERE user=?;
> query_userinfo SELECT uid, gid, home AS directory FROM users WHERE 
> REPLACE(email, '@', '_')=?;
> 
> But if you don't have aliases per se you can do a similar REPLACE
> inside query_alias, or if you want your aliases table a little shorter
> you can probably use some union query, or you can come up with your
> own unique solution.
> 
> martijn@
> 
> On 11/28/25 22:13, Albert ARIBAUD wrote:
> > Hello,
> > 
> > I have set up OpenSMTPd to match on a SQLite databae of virtual users
> > and invoke an lmtp action as follows:
> > 
> > ----------------------
> > table virtual-users sqlite:/etc/smtpd-sqlite.conf
> > 
> > action "lmtp_dovecot" lmtp "/run/dovecot/lmtp" rcpt-to userbase
> > <virtual-users>
> > 
> > match from any for domain <virtual-users> rcpt-to <virtual-users>
> > action "lmtp_dovecot"
> > ----------------------
> > 
> > Here an extract of the log showing the matches and subsequent
> > expand_insert when receiving and "RCPT TO:<[email protected]>":
> > 
> > ---------------
> > lookup: match "aribaud.net" as domain in table proc:virtual-users ->
> > true
> > lookup: match "[email protected]" as mailaddr in table proc:virtual-
> > users -> true
> > rule #1 matched: match from any for domain virtual-users rcpt-to
> > virtual-users action lmtp_dovecot
> > expand: 0xaaaadba55578: expand_insert() called for
> > username:albert[parent=0xaaaadb9f27e0, rule=0xaaaadb9ea490,
> > dispatcher=0xaaaadb9ea560]
> > expand: 0xaaaadba55578: inserted node 0xaaaadb9f2d50
> > expand: lka_expand: username: albert [depth=1, sameuser=0]
> > lookup: lookup "albert" as userinfo in table proc:virtual-users -> none
> > --------------
> > 
> > I can see that the virtual-users table properly returns success for the
> > domain  query on "aribaud.net", and also returning success for the
> > mailaddr query on "[email protected]".
> > 
> > But then, the userinfo query is done on "albert" alone, which won't
> > work because the database contains user info for [email protected],
> > not for albert.
> > 
> > Is there a way to get OpenSMTPd to look up userinfo using the complete
> > email address as the key?
> > 
> > Regards,
> > Albert.
> > 

Reply via email to