4

I'm sending my emails using Postfix, and I've got a considerable list of emails to send newsletters to. So I prefer to pack my SMTP requests into one by setting one of emails as To and a bunch more as Bcc (in PHP).

My problem is that if one of the emails is invalid, Postfix rejects the whole request prompting the following error:

5.1.1 : Recipient address rejected: User unknown in local recipient table

It would be great if I could configure Postfix in a way so it dumps the invalid one but sends the rest. I know I can validate the addresses myself before using them in an email but I prefer it if it is done by Postfix.

[UPDATE]

Here's the maillog's content:

Nov 18 16:20:28 mail postfix/smtpd[12922]: 14A5FB812E1: client=localhost[127.0.0.1]
Nov 18 16:20:28 mail postfix/smtpd[12922]: 14A5FB812E1: reject: RCPT from localhost[127.0.0.1]: 550 5.1.1 <mehran_hotmail.com>: Recipient address rejected: User unknown in local recipient table; from=<mehran@localhost> to=<mehran_hotmail.com> proto=ESMTP helo=<localhost>

This error is generated while I tried to send an email with [email protected] as the main recipient and mehran_hotmail.com as the Bcc.

[UPDATE]

Here's the complete log associated with the request:

Nov 19 09:47:01 mail postfix/smtpd[20947]: connect from localhost[127.0.0.1]
Nov 19 09:47:01 mail postfix/smtpd[20947]: EC281B81BCE: client=localhost[127.0.0.1]
Nov 19 09:47:01 mail postfix/smtpd[20947]: warning: Illegal address syntax from localhost[127.0.0.1] in RCPT command: <mehran@?????.com>
Nov 19 09:47:01 mail postfix/smtpd[20947]: disconnect from localhost[127.0.0.1]

This is a new scenario (leading to the same problem) in which I used a correct email address (both To and Bcc hold correct email addresses but not the same address) but this time the email address is rejected because Postfix does not recognize it. I used non-ASCII characters as for the domain name (mehran@مهران.com). I don't care whether Postfix supports non-ASCII addresses or not, it's just that when it rejects one address, the whole request is rejected!! And no email is sent to [email protected] (which is named in To)!

Now the returned error message to my code (PHP made MUA) is:

5.1.3 Bad recipient address syntax

As for my PHP code which interacts with SMTP server:

$mail = new \Zend_Mail('utf-8');
$mail->setMessageId($mail->createMessageId());

foreach ($array_to as $to) {
    $mail->addTo($to['email'], $to['name']);
}
foreach ($array_cc as $to) {
    $mail->addCc($to['email'], $to['name']);
}
foreach ($array_bcc as $to) {
    $mail->addBcc($to['email'], $to['name']);
}

$mail->setSubject($subject);
$mail->setBodyHtml($body);
$mail->setFrom($current_user_email, $current_user_name);
$mail->setDate(new \Zend_Date());

$smtp = createSmtpConnection();
$smtp->send($mail);

As you can see I used Zend Framework (v1) and my code is rather simple. The $array_* variables are simple arrays holding the email addresses. In my test scenario there are only two email addresses, one for To and one for Bcc.

5
  • 1
    Don't BCC, use individual mails. Inefficient, maybe, but that's how it works. Nov 18, 2014 at 12:36
  • @masegaloeh I've updated the log, and that's all there is to it. It's just that I've replaced my domain with localhost!
    – Mehran
    Nov 18, 2014 at 13:35
  • Well that's strange. In my case, whenever one recipient was rejected but the another wasn't, postfix still allow the deliveries for passed recipient. For example see the maillog pastebin.com/AbEHBgY0.
    – masegaloeh
    Nov 18, 2014 at 13:55
  • There's nothing wrong with my PHP code or Postfix configuration. I can say that since the mail is sent smoothly if I give Postfix all valid address. I was hoping there's a configuration which tell Postfix to reject invalid addresses only, and go on with the valid ones. But now it just rejects them altogether.
    – Mehran
    Nov 18, 2014 at 14:48
  • OK, please show the full maillog. From entry postfix/smtpd[19685]: connect from client.ip.address until disconnect from client.ip.address. This will show the full smtp transaction.
    – masegaloeh
    Nov 19, 2014 at 3:46

3 Answers 3

9

TLDR: Your case is abnormal behavior mail client in proper SMTP transaction. Maybe something wrong in your PHP code. See this thread on postfix mailing list. A quote from Postfix author in that thread

You are mistaken. You have no evidence whatsoever that Postfix rejects the entire message.

It is known that SOME SMTP CLIENT programs will give up delivering a message when one recipient is not accepted, even when the other recipients are good.


How is SMTP rejection works

First, we will take the tour of SMTP transaction. Below is how SMTP works in low level. You can always try it via telnet/netcat.

Case 1 This is the transaction when there is a single recipient.

S: 220 smtp.example.net Simple Mail Transfer Service Ready
C: HELO client.example.com
S: 250 Hello client.example.com
C: MAIL FROM:<[email protected]>
S: 250 OK
C: RCPT TO:<[email protected]>
S: 250 OK
C: DATA
S: 354 Send message content; end with <CRLF>.<CRLF>
C: The message data (body text, subject, e-mail header, attachments etc) is sent
C: .
S: 250 2.0.0 Ok: queued as D7D3E84403
C: QUIT
S: 221 Bye

So, SMTP is chatty protocol, every time the client issuing command (HELO/MAIL/RCPT/DATA/QUIT), the server should answer it before the transaction continue. In this case all the answer has code 250, or in human languange I accepted it.

Case 2 SMTP transaction for multiple recipients

S: 220 smtp.example.net Simple Mail Transfer Service Ready
C: HELO client.example.com
S: 250 Hello client.example.com
C: MAIL FROM:<[email protected]>
S: 250 OK
C: RCPT TO:<[email protected]>
S: 250 OK
C: RCPT TO:<[email protected]>
S: 250 OK
C: RCPT TO:<[email protected]>
S: 250 OK
C: DATA
S: 354 Send message content; end with <CRLF>.<CRLF>
C: The message data (body text, subject, e-mail header, attachments etc) is sent
C: .
S: 250 2.0.0 Ok: queued as D7D3E84403
C: QUIT
S: 221 Bye

In this example there are three recipient. We are using multiple RCPT command in single transaction. RCPT command is special command. This command can be repeated multiple times for a given e-mail message in order to deliver a single e-mail message to multiple recipients.

Case 3 If some recipients rejected (but not all), the transaction was continued. Here the sample transaction.

S: 220 smtp.example.net Simple Mail Transfer Service Ready
C: HELO client.example.com
S: 250 Hello client.example.com
C: MAIL FROM:<[email protected]>
S: 250 OK
C: RCPT TO:<[email protected]>
S: 250 OK
C: RCPT TO:<[email protected]>
S: 550 5.1.1 <[email protected]>: Recipient address rejected: User unknown in local recipient table
C: RCPT TO:<[email protected]>
S: 250 OK
C: DATA
S: 354 Send message content; end with <CRLF>.<CRLF>
C: The message data (body text, subject, e-mail header, attachments etc) is sent
C: .
S: 250 2.0.0 Ok: queued as D7D3E84403
C: QUIT
S: 221 Bye

Why the server still accept the email? Because there are two valid recipients beside one invalid one.

Disclaimer: Above resources taken from here.


(unsuccessful) Attempt to Reproduce the Problem

OK, I have tried to reproduce your problem in my box. This is my PHP code with library PHPMailer. (I don't familiar with zend Framework)

<?php
require '../PHPMailerAutoload.php';

$internaldomain = 'in.example.com';
$externaldomain = 'ex.example.com';

$mail = new PHPMailer;

$mail->isSMTP();
$mail->SMTPDebug = 2;
$mail->Host = "smtp6.example.com";
$mail->Port = 25;
$mail->SMTPAuth = false;

$mail->setFrom('from@' . $internaldomain, 'First Last');
$mail->addAddress('valid@' . $externaldomain, 'valid 1');
$mail->AddBCC('bounce@' . $internaldomain, 'valid 3');
$mail->AddBCC('invaliduser@' . $internaldomain, 'invalid user');
$mail->AddBCC('root@' . $internaldomain, 'valid 4');

$mail->Subject = 'PHPMailer SMTP test';
$mail->IsHTML(false);
$mail->Body    = "This is test";

if (!$mail->send()) {
    echo "Mailer Error: " . $mail->ErrorInfo;
} else {
    echo "Message sent!";
}

Because SMTPDebug has enabled, the output contains full SMTP transaction. This output similar with above example.

SERVER -> CLIENT: 220 smtp6.example.net ESMTP at your service
CLIENT -> SERVER: EHLO web.example.net
SERVER -> CLIENT: 250-smtp6.example.net
                  250-PIPELINING
                  250-SIZE 10240000
                  250-VRFY
                  250-ETRN
                  250-ENHANCEDSTATUSCODES
                  250-8BITMIME
                  250 DSN
CLIENT -> SERVER: MAIL FROM:<[email protected]>
SERVER -> CLIENT: 250 2.1.0 Ok
CLIENT -> SERVER: RCPT TO:<[email protected]>
SERVER -> CLIENT: 250 2.1.5 Ok
CLIENT -> SERVER: RCPT TO:<[email protected]>
SERVER -> CLIENT: 250 2.1.5 Ok
CLIENT -> SERVER: RCPT TO:<[email protected]>
SERVER -> CLIENT: 550 5.1.1 <[email protected]>: Recipient address rejected: User unknown in local recipient table
SMTP ERROR: RCPT TO command failed: 550 5.1.1 <[email protected]>: Recipient address rejected: User unknown in local recipient table
CLIENT -> SERVER: RCPT TO:<[email protected]>
SERVER -> CLIENT: 250 2.1.5 Ok
CLIENT -> SERVER: DATA
SERVER -> CLIENT: 354 End data with <CR><LF>.<CR><LF>
CLIENT -> SERVER: Date: Wed, 19 Nov 2014 09:28:16 +0700
CLIENT -> SERVER: To: valid 1 <[email protected]>
CLIENT -> SERVER: From: First Last <[email protected]>
CLIENT -> SERVER: Subject: PHPMailer SMTP test
CLIENT -> SERVER: Message-ID: <[email protected]>
CLIENT -> SERVER: X-Priority: 3
CLIENT -> SERVER: X-Mailer: PHPMailer 5.2.9 (https://github.com/PHPMailer/PHPMailer/)
CLIENT -> SERVER: MIME-Version: 1.0
CLIENT -> SERVER: Content-Type: text/plain; charset=iso-8859-1
CLIENT -> SERVER: Content-Transfer-Encoding: 8bit
CLIENT -> SERVER:
CLIENT -> SERVER: This is test
CLIENT -> SERVER:
CLIENT -> SERVER: .
SERVER -> CLIENT: 250 2.0.0 Ok: queued as D7D3E84403
CLIENT -> SERVER: QUIT
SERVER -> CLIENT: 221 2.0.0 Bye

and the maillog entry

Nov 19 09:28:16 cache postfix/smtpd[14865]: D7D3E84403: client=unknown[192.168.192.100]
Nov 19 09:28:16 cache postfix/smtpd[14865]: D7D3E84403: reject: RCPT from unknown[192.168.192.100]: 550 5.1.1 <[email protected]>: Recipient address rejected: User unknown in local recipient table; from=<[email protected]> to=<[email protected]> proto=ESMTP helo=<web.example.net>
Nov 19 09:28:16 cache postfix/cleanup[14867]: D7D3E84403: message-id=<[email protected]>
Nov 19 09:28:17 cache postfix/qmgr[1200]: D7D3E84403: from=<[email protected]>, size=617, nrcpt=3 (queue active)
Nov 19 09:28:17 cache postfix/local[14870]: D7D3E84403: to=<[email protected]>, relay=local, delay=0.21, delays=0.21/0/0/0, dsn=2.0.0, status=sent (delivered to mailbox)
Nov 19 09:28:17 cache postfix/smtp[14869]: D7D3E84403: to=<[email protected]>, relay=example.org[192.168.3.3]:25, delay=0.22, delays=0.21/0/0/0.01, dsn=2.0.0, status=sent (250 2.0.0 Ok: queued as 3jj7Hj0pM3z5Twh)
Nov 19 09:28:17 cache postfix/local[14868]: D7D3E84403: to=<[email protected]>, relay=local, delay=0.23, delays=0.21/0/0/0.02, dsn=2.0.0, status=sent (forwarded as 165E084404)
Nov 19 09:28:17 cache postfix/qmgr[1200]: D7D3E84403: removed

Well looks like in my box, postfix and PHPMailer behave in normal circumstances. You can use this to compare with maillog in your box :)

3
  • You are right. Talking directly to SMTP server and giving it the invalid address works. Which means there's a problem with ZF. Thanks a lot.
    – Mehran
    Nov 19, 2014 at 8:40
  • 1
    Because the you have confirmed that problem source is ZF, you can reask again this question in StackOverflow or you can solved it yourself. Good luck :)
    – masegaloeh
    Nov 19, 2014 at 8:42
  • The transcripts do a very good job of illustrating the behaviour upon encountering invalid/unknown users in RCPT TO. Mozilla thunderbird, sadly, still refuses to continue with mail sending upon encountering a single 5xx in the RCPT TO stage, even in 2019.
    – Nubarke
    Apr 13, 2019 at 14:08
1

That's not really the way mail servers work. They're designed to either send the mail through, or return the error/reason for failure to the end user if something does not work. Changing that behavior changes the way SMTP functions.

As the Wiki page on NDRs says:

NDRs are a basic SMTP function. As soon as an MTA has accepted a mail for forwarding or delivery it cannot silently delete ("drop") it; it has to create and send a bounce message to the originator if forwarding or delivery failed.

4
  • I'm totally ok with bouncing the mail associated with the invalid address, but I expect the remaining mails to be delivered. But as soon as I press the send button, Postfix rejects the whole request by returning the mentioned error message!
    – Mehran
    Nov 18, 2014 at 12:46
  • Which is the way it's supposed to work, since you're sending one message to the server (do as suggested and split the messages up). Imagine the confusion if a mail server didn't tell you that you had spelled addresses wrong, it could be days before the other side says "weren't you supposed to send me...". That's just one scenario, it's better that this behavior remains.
    – NickW
    Nov 18, 2014 at 12:51
  • I was hoping I could postpone the validation step after the mail is split into individual addresses!!
    – Mehran
    Nov 18, 2014 at 12:54
  • Hmmm, that's an interesting idea.. I'm not sure about how one might go about that, you might even have to edit the source code. Possibly someone on the postfix list could help you with that.
    – NickW
    Nov 18, 2014 at 13:28
-1

Modify your Postfix/main.cf file by uncommenting the following entry in the file. Restart postfix and try sending again.

local_recipient_maps

What was happening in email application client trying to send email is different from you performing a test via command line as the email flow is allowed in the command line to continue but failed immediately a bad local address is detected.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .