3

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.

Greg
  • 198
  • 10
  • Do you want "reject email to this user (regardless of email content)" or "reject this email to all recipients"? I have problems translating your requirements to "sendmail terminology". – AnFi May 04 '16 at 21:25
  • Does that matter in terms of what is being asked? Is it possible to do either from procmail? If yes, then that satisfies my question. By rejecting I DO NOT mean bouncing the email (sending back a bounce message: https://en.wikipedia.org/wiki/Bounce_message). I mean not accepting the email during the SMTP conversation. This is not to say that a bounce won't be produced, it may be produced, but if it is produced then it won't be from my MTA but from the other sendmail MSA that is trying to deliver email to the account on my server. – Greg May 04 '16 at 22:26
  • Classic recipe for rejecting bad virtual recipients is to list good ones (e.g. in virtusertable) and make sendmail reject all remaining in the domain. Other obvious recipes are full of "side effects". It means that they do not fit to well to non "very specific" situations. – AnFi May 05 '16 at 08:02
  • I do have only specific users listed in the access table. All other users are rejected automatically. Those emails I was thinking I could reject now are addressed to valid users. The addresses were probably harvested. There are some cases when the same email arrives over and over again, with a random sender and delivery path but similar content. I was thinking about rejecting them early in the receiving process rather than accepting them and filtering out from the user mailbox. – Greg May 05 '16 at 09:05

3 Answers3

2

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?)

tripleee
  • 1,324
  • 3
  • 14
  • 24
  • Thank you for the comprehensive explanation! Two questions if I may. Assuming that the SMTP isn't completed by the time procmail is parsing DATA, would the behaviour of sendmail in terms of produced error and bounced email differ when compared to parsing the same DATA and rejecting with the same error in a milter? And which sendmail is producing the bounce message when the email is rejected early in the process, e.g. when another sendmail is trying to deliver email to a non-existent user or is blocked by its IP? I assumed it would be the other sendmail, which tried to connect but couldn't? – Greg May 06 '16 at 07:09
  • Not too familiar with the milter architecture, but my general impression is that it gets involved earlier in the process, precisely so that you can handle things early on in the SMTP session. Not sure what you mean by "which sendmail" -- the remote MTA which is connecting to your server would produce the actual bounce message if its delivery attempt is rejected by your server. (There is no guarantee that the remote client is Sendmail, or an MTA at all, though.) – tripleee May 06 '16 at 07:21
  • In concrete terms, if your server says "570 go away" instead of "200 success" then that is all that your server is transmitting, and the connecting client does whatever it does with that information. A standards-conformant MTA would generate a bounce message (provided it's not a double bounce, etc, as alluded to in my answer) and a standards-compliant mail client would probably do something similar -- maybe a dialog box showing your server's error message. – tripleee May 06 '16 at 07:24
  • Answering your question, from what I could check the emails are being send from random IP addresses, most likely a zombie network. I didn't check if they are blocked by DNSBLs. Back to your comment, you wrote that if the email is rejected by procmail after SMTP transaction has been completed the server will attempt to connect back to the sender's MX server to deliver the bounce. That's why I asked which side is producing the bounce message. – Greg May 06 '16 at 07:29
  • I added an example to the question to make it more clear what behaviour I am after. – Greg May 06 '16 at 08:25
  • As outlined above, returning an SMTP error code will produce an error message somewhere. There is no way to return a result midway through the `DATA`; you either accept it (250) or fail (4xx or 5xx) at the end of the `DATA`. You are probably looking for something which would drop the TCP connection instead, which will make some zombies go away forever, and some compliant implementations retry for a few days, then finally return a bounce message. – tripleee May 06 '16 at 09:39
  • Yeah, so I guess that's probably something that's not possible with procmail or milter, would need to be supported in MTA. I wonder if any MTA does support that, and if not, why not. Probably because they don't want to rejects emails like that, rather send them to a spam folder so that user can review if they want to. – Greg May 06 '16 at 14:21
  • On the contrary, it is of paramount importance for many high-traffic sites to block the spam as early as possible, before it consumes network bandwidth, disk quota, and admin patience. You can do these things with a milter, I believe. – tripleee May 06 '16 at 20:48
  • Notice also now a follow-up question from another user trying to implement this in Postfix: https://serverfault.com/questions/1095290/procmail-not-bouncing-emails – tripleee Mar 04 '22 at 10:02
1

I think that procmail acts as a local mailer which is run after the email is accepted. Basically, it is a next step in the delivery. So it can't affect the connection which is accepting the email to the sendmail process. Think about a different example when you send the email locally to another local user. It is first accepted to the sendmail process and if the other local user is missing, you will get an error message by another email.

Petr Chloupek
  • 254
  • 1
  • 6
  • That well might be the case but I would love if your answer was a bit more convincing that it indeed is the case :) – Greg May 04 '16 at 12:50
  • I don't know if it does count, but i read this about 15 years ago: http://www.amazon.com/sendmail-4th-Bryan-Costales/dp/0596510292/ref=sr_1_1?ie=UTF8&qid=1462366507&sr=8-1&keywords=sendmail and I do use sendmail ever since on my servers. – Petr Chloupek May 04 '16 at 12:56
  • I do have that book and use it regularly. It's an over 1300 pages' long reference manual, in which finding answers to questions 'if something is possible' is extremely difficult. Finding answers to questions 'how to do something' or 'where to do that' are easier. And even if something isn't in the book doesn't necessarily mean that it's impossible to do. – Greg May 04 '16 at 13:16
  • Petr Chloupek, yes I understand that. If what I am asking for is possible then my setup would need to be probably changed as well, if possible. I only mentioned my setup hoping that it will bring more relevant answers. – Greg May 04 '16 at 13:18
  • sorry, i deleted the last comment as irrelevant. what is your scenario anyway, maybe it would be better to start with what you need to achieve. Maybe there is a better way how to do it. – Petr Chloupek May 04 '16 at 13:21
  • I am just wondering if that's possible, for my own knowledge and better understanding of the SMTP, sendmail, and procmail chain. If it worked then I would probably think about using it to reject specific emails (based on the content of that email, e.g. regular spam, where it's possible). – Greg May 04 '16 at 13:27
1

Have you considered using milter (e.g. MIMEDefang.org milter)?
MIMEDefang behaviour is controlled by customizable perl scrip. It should be possible to get rejects in smtp session based on message content. It will also make the solution portable to other MTAs e.g. postfix.

Classic MIMEDefang examples include rejecting messages with high SpamAssassin (spamines) scores. It may alone block most of such emails.

AnFi
  • 5,883
  • 1
  • 12
  • 26
  • Great, thanks for bringing that up. It's probably what I am looking for but not exactly an answer to my question :) This document about milters https://www.roaringpenguin.com/files/filtering-with-milter.pdf says that the SMTP transaction is complete by the time procmail is invoked (on page 5), however other resources, like this one http://www.diablotin.com/librairie/networking/sendmail/ch24_03.htm say that the mail isn't delivered until the A= program (sh that invokes the procmail) returns with `EX_OK`. Otherwise it produces a bounce mail. But milter may be a better option overall. – Greg May 05 '16 at 15:17
  • 1) I have some experience in fixing the real problem instead of implementing "suboptimal" solutions ;-) 2) You may make sendmail delay "final dot ACK" but it would solve deliveries to single procmail virtual recipient. "Mixed recipients" would be a mess and it would create problems elsewhere. – AnFi May 05 '16 at 16:05
  • But in terms of possibility, it is possible to reject the email in procmail? However, it's not the best option because of the "Mixed recipients" issue that you mentioned. The correct or better approach would be to use milters. Would you be able to expand your answer a bit explaining the problem with rejecting an email in procmail and I would gladly accept it? – Greg May 05 '16 at 16:31
  • I think in may/should be possible with `DeliveryMode=interactive` (synchronous). **BUT** I have not used or tested it and I have no time to search for **authoritative** answer. Anyway `interactive` is not recommended for "general use". **I would like to avoid putting my guesses into the answer**. – AnFi May 05 '16 at 17:03
  • Does it mean that <<"Mixed recipients" would be a mess and it would create problems elsewhere.>> was a guess? – Greg May 05 '16 at 19:34
  • I think it's safe to say that a solution which should reject and accept a message at the same time would be hard to specify properly. – tripleee May 06 '16 at 07:18
  • @Amiramix It was a guess with assumed VERY high probability. – AnFi May 06 '16 at 07:42
  • I added an example to the question to make it more clear what behaviour I am after. – Greg May 06 '16 at 08:25