Score:1

postfix: conditionally ignoring certain "User unknown in virtual mailbox table" errors when using a milter

by flag

Note: I originally posted this question in Unix/Linux StackExchange, but after a week, there have been no responses. I see more postfix-related discussion here, and so I've voted to close the StackExchange version of my question, and I've moved my question here.

I'm running postfix version 2.93 under Debian 8, and I'm trying to accomplish something unusual.

I have been using a home-grown milter for years which is working well. It runs various tests at each stage of the SMTP dialog: ehlo, mail from, rcpt to, etc.

I have configured postfix to do its standard checking for "User unknown in virtual mailbox table", and that is also working as it's supposed to.

However ...

In certain rare cases, I'd like to intercept the incoming message during the rcpt to stage, before postfix determines "User unknown in virtual mailbox table", and if these messages come from a small group of certain select senders and are addressed to a small group of specific unknown recipient names, I want to process them differently than normal via that milter step.

There is enough information available during the rcpt to milter step in order to perform this special processing, but unfortunately, the "User unknown in virtual mailbox table" postfix processing already rejects messages to unknown users before the rcpt to milter step is invoked, and therefore that milter step never gets performed.

Is there a way to configure postfix to only reject messages with "User unknown in virtual mailbox table" if the sender name does not not match certain special patterns?

If so, postfix could continue to automatically reject messages to most unknown users, and it could then pass only those rare, special messages on to the milter for them to be handled during the rcpt to step.

I know that I could completely disable the postfix unknown recipient tests and then manage this myself during my rcpt to milter step for all incoming messages. However, if possible, I'd like to avoid this and somehow tell postfix to conditionally reject most messages to unknown users and to only pass a small subset of those incoming messages from special senders on to the milter processing.

I'm not optimistic about this even being possible under postfix, but perhaps one or more of you know of a way that I could accomplish this unusual task.

Thank you very much for any thoughts and suggestions.

Ginnungagap avatar
gu flag
Debian 8 is EoL and questions on SF assume normal business practices which include not running obsolete software. I'm not voting to close the question because it remains viable nonetheless but be aware you'd better update anyway.
HippoMan avatar
by flag
Thank you. Unfortunately, I do not have control over the software and OS versions that are installed on the host I am using. I have begged the powers that be to upgrade their OS, and until they do, I am stuck in this environment. Nonetheless, I would like to resolve this issue which I think is purely postfix-related and not Debian-version-related, and so thank you very much (!!!) for allowing this question to remain here. I hope to move to a newer OS sooner rather than later (fingers crossed!).
HippoMan avatar
by flag
If I can selectively get the recipient to be accepted by postfix even though it's an unknown recipient whose address matches my special criteria, I then want my RCPT TO milter handler to log it in a database that I am using to document certain spammers, so I can generate reports to ISP's where the spam comes from, and then return something like "550 unknown recipient" from the RCPT TO milter. I might want to perform other functions on these spam addresses, as well.
Score:0
fr flag
anx

The right-hand side of a check_sender_access lookup in a smtpd_*_restrictions list can in turn contain named conditional restrictions (documented in the RESTRICTION_CLASS_README file). This means if the criteria for rejecting messages to unknown recipients is solely‡ dependant on the rfc5321.MailFrom ("envelope sender"), then moving the reject_unverified_recipient statement from a the smtpd_*_restrictions list itself, into a sender-dependant lookup should do the trick:

# OLD (example, you get the idea)
smtpd_recipients_restrictions =
    reject_unauth_destination,
    reject_unknown_recipient_domain,
    reject_unverified_recipient

# NEW (just a single replacement, adapt to your OLD version)
smtpd_recipients_restrictions =
    reject_unauth_destination,
    reject_unknown_recipient_domain,
    check_sender_access pcre:/etc/postfix/maps/no-recipient-lookups.pcre

# /etc/postfix/maps/no-recipient-lookups.pcre
/.*@example.org/   DUNNO
/./                reject_unverified_recipient

For each listed sender (or any other single check_*_access condition), this skips the "Does this recipient exist?" check, and for all other senders, it will enforce that check.

Now, this whole exercise pretty much only makes sense if you are later unconditionally reject any messages receiving this special treatment, because what is postfix going to do with messages it should have already checked earlier that it won't be able to deliver them. You should never emit non-delivery reports in cases where SMTP-stage rejections would have been possible. If your milter only needs the message headers (as your use case of investigating abuse suggests) you may be able to guarantee this by adding the unconditional restriction also in the smtpd_end_of_data_restrictions list (expect of minor performance implications in case this 2nd lookup races with the address verification process).


‡ If not, you can implement the decision of whether the special case is applicable in a check_policy_service, which lets you more complex decisions then a simple (or regex) lookup on the sender, e.g. you could parse the rfc5322.From (headers indicating sender) there. The only difference is, that instead of writing two lines of no-recipient-lookups.pcre file, you have to write/adapt and run a policy daemon that returns the reject_unverified_recipient result, analogous of how your Milter currently return SMTP status codes.

HippoMan avatar
by flag
Aha! The "check_sender_access" directive is exactly what I'm looking for! I see that it can take PCRE regex's and this is perfect for filtering what I want. That small set of filtered messages will then get forwarded to my RCPT TO milter handler, at which time I can do what I want with them. Thank you very much!!!!
HippoMan avatar
by flag
Hmm ... yes, I see. However, the problem is that there are massive floods of spam that I am already blocking, and with the opt-in flag, all of those would be opted in and would have to be re-filtered by the milter, just so that I can block the small handful of spams that I want to treat in a special way. If I DUNNO on all messages from the offending sender, then I can allow "postmaster@..." and block the other special stuff in my RCPT TO milter handler. Or am I still misunderstanding something?
anx avatar
fr flag
anx
Opting in to see rejected recipients in your milter should not substantially increase its resource usage - SMTP conversations without *any* accepted recipient are not proceeding to the DATA stage, so it is really mostly about rare multi-recipient cases.
HippoMan avatar
by flag
Oh, I misunderstood. I see now that you're talking about a *multi-recipient* message with (for example) one recipient being `postmaster` and the other being `dirtyspammer`. OK, I see now how opt-in can help me. Thank you again.
HippoMan avatar
by flag
One more quick question: I can't find any docs about the milter "opt-in" flag for rejected messages. Could you or anyone point me to such docs? Thank you very much!
anx avatar
fr flag
anx
@HippoMan The mechanism to tell the server how to treat the milter is called *option negotiation* (`SMFIC_OPTNEG`). On the wire, Postfix sends a bitmask indicating the offered protocol and the Milter application replies with the subset it supports/wants. The option I wanted to make you aware of is described as *also send rejected RCPTs* (`SMFIP_RCPT_REJ`) and the resulting extra calls can be identified via the `{rcpt_mailer}` macro. The implementation details may or may not be abstracted a bit and accessed through differently prefixes names in the library you are using to build your milter.
anx avatar
fr flag
anx
(I could tell you to navigate to the `libmilter/docs/` folder in a recent sendmail source tarball because that more or less applies to how Postfix is implementing the same interface. But you probably do not need the documentation for the C library, but instead for whatever binding/reimplementation you are actually using, so just find the place that mentions similar keywords or notes things newly added for `Sendmail 8.14.0`)
HippoMan avatar
by flag
Thank you for all that!!
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.