Is it possible to reject certain emails in procmail? [In SMTP session rejects based on email content]

emailprocmailsendmailsmtp

Let's assume a typical setup where procmail is called from sendmail to filter incoming emails into correct mailboxes. Is that done while the incoming SMTP connection to sendmail is still active or is it being done after the email has already been accepted?

If the former then I understand it could be possible for procmail to return to sendmail an error so that sendmail replies with an error code, for example 554 Transaction failed while accepting the SMTP DATA, instead of the usual 200?

In my case sendmail calls procmail from the aliases database with entries like this:

theaddres:   theaddres-somedomain-com.virtual

theaddres-somedomain-com.virtual:   |"/usr/libexec/sm.bin/someuser.virtual somedomain@theaddress"

Which then executes the procmail script:

root@mda:/etc/mail # less /usr/libexec/sm.bin/someuser.virtual 
/usr/local/bin/procmail -a $1 /usr/local/etc/procmailrc/someuser.virtual

EDIT:

Adding a more detailed explanation. Firstly, I would like to establish if the flow outlined below, which is based on Wikipedia's example, is possible in SMTP protocol at all. If yes, then if it would be possible with procmail. Then, if no (which I guess is the case), if there exists an implementation (e.g. milter) in which it would be possible.

S: 220 smtp.example.com ESMTP Postfix
C: HELO relay.example.org 
S: 250 Hello relay.example.org, I am glad to meet you
C: MAIL FROM:<bob@example.org>
S: 250 Ok
C: RCPT TO:<alice@example.com>
S: 250 Ok
C: RCPT TO:<theboss@example.com>
S: 250 Ok
C: DATA
S: 354 End data with <CR><LF>.<CR><LF>
C: From: "Bob Example" <bob@example.org>
C: To: "Alice Example" <alice@example.com>
C: Cc: theboss@example.com
C: Date: Tue, 15 January 2008 16:02:43 -0500
C: Subject: Test message
C: 
C: Hello Alice.
C: This is a test message with 5 header fields and 4 lines in the message body.

Now this is what I would like to see:
S (after receiving the first 2 lines out of 4): 452 Requested action not taken: insufficient system storage
C: QUIT
S: 221 Bye
{The server closes the connection}

So, the server stops receiving the email (e.g. because it detected in the email the sequence "This is a test message") and replies to the client with an error. In this case it's 452 but it could be any error valid in response to the DATA request. And the client may or may not respond with QUIT, I don't care.

This probably depends on how the SMTP protocol is implemented on the TCP level. Can I limit the amount of DATA received from the client to, lets say, 50 initial bytes (e.g. by limiting the size of the TCP frame)? Does the SMTP protocol allow me to reply with an error while the client is sending the content of DATA?

Also, if the server disconnected purposefully after receiving the initial part of DATA (instead of trying to send to the client an error) it would be no different to the TCP connection being accidentally dropped while transmitting the email. A well behaving MTA would try to reconnect and redeliver the email, a spammer wouldn't probably bother retrying.

Best Answer

What you are describing is perfectly feasible, but Sendmail will produce a bounce message in this situation; that's part of the protocol design. The way to do this is to have Procmail abort with a suitable exit code, to communicate the bounce reason back to Sendmail.

For example, to return a "user unknown" error,

:0
* ^Received: from badhelo \(badhost \[10\.9\.8\.7\]\) by yourhost
{ EXITCODE=67 HOST= }

The EXITCODE specifies which return code to exit with, and reassigning HOST has the obscure but well-documented side effect of abandoning the current recipe file immediately.

See http://www.iki.fi/era/procmail/mini-faq.html#exitcode for more details, and e.g. sysexits.h for a list of the actual exit codes.

This needs to be in your personal .procmailrc, not in /etc/procmailrc

You will not have control over whether this happens during or after the SMTP transaction has completed. My recollection from when Sendmail was still popular was that it would in fact process the Procmail rules while the message was being received, but that is an implementation detail which could depend on various circumstances, and perhaps change between versions. Either way, SMTP is a store-and-forward protocol; if the transaction fails and the client has already disconnected, the server will attempt to connect back to the sender's MX server to deliver the bounce. (There are situations where this is undesirable; so for example, a bounce for a bounce should not be generated and delivered.)

Either way, in order for Procmail to be able to process anything, you will need to have already received the entire message; explicitly failing the SMTP DATA transaction at this late stage is rather pointless, as you cannot undo receiving. If you want to ditch a message silently once the DATA has completed, just deliver it to /dev/null.

That said, it is beneficial to reject as early as possible. If you can implement an IP-level block against the bad senders, that would be a lot simpler and gentler on the network stack. (Between the lines I'm reading "zombie network" -- do you know if these senders are blocked e.g. by the Spamhaus DNSBLs?)

Related Topic