Postfix rejects an outgoing email with multiple destinations due to one invalid address
Solution 1:
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 :)
Solution 2:
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.