Branch for testing SMTP message limit patch by Carl Corliss

This commit is contained in:
Marcus Bointon 2008-11-20 21:06:15 +00:00
parent 5aeead7e70
commit 76a3eb79b1
2 changed files with 135 additions and 46 deletions

View File

@ -527,6 +527,41 @@ class PHPMailer {
return true;
}
/**
* Sends out the list of recipients to the smtp server, checking
* for a 45X failure while doing so.
*
* @param Array $recipients List of recipients to set up
* @param Array &$bad_recipients Reference to an array that will be filled with the list of recipients who failed during this run
* @param Bool &$was_throttled Reference to a boolean that will bet set based on whether or not the connection appeared to be throttled
* @param Integer &$throttle_total Reference to a total that will be set to the total recipients that were successfully added if throttling happened
* @access public
* @return Bool
* Carl Corliss <rabbitt at users.sourceforge.net>
*/
function SmtpSend_AddRecipients($recipients, &$bad_recipients = array(), &$was_throttled = false, &$throttle_total = -1) {
$total_recipients = count($recipients);
$return_value = true;
for ($i = 0; $i < $total_recipients; $i++) {
if (!$this->smtp->Recipient($recipients[$i])) {
$error = $this->smtp->getLastError();
if (isset($error['smtp_code']) &&
($error['smtp_code'] == 451 || $error['smtp_code'] == 452)) {
$was_throttled = true;
$throttle_total = ($i - 1);
$return_value = false;
break;
} else {
$bad_recipients[] = $recipients[$i];
$return_value = false;
}
}
}
return $return_value;
}
/**
* Sends mail via SMTP using PhpSMTP
* Returns false if there is a bad MAIL FROM, RCPT, or DATA input.
@ -537,7 +572,6 @@ class PHPMailer {
*/
public function SmtpSend($header, $body) {
include_once($this->PluginDir . 'class.smtp.php');
$error = '';
$bad_rcpt = array();
if(!$this->SmtpConnect()) {
@ -546,55 +580,86 @@ class PHPMailer {
$smtp_from = ($this->Sender == '') ? $this->From : $this->Sender;
if(!$this->smtp->Mail($smtp_from)) {
$error = $this->Lang('from_failed') . $smtp_from;
$this->SetError($error);
$this->SetError($this->Lang('from_failed') . $smtp_from);
$this->smtp->Reset();
return false;
}
/* Attempt to send attach all recipients */
for($i = 0; $i < count($this->to); $i++) {
if(!$this->smtp->Recipient($this->to[$i][0])) {
$bad_rcpt[] = $this->to[$i][0];
}
}
for($i = 0; $i < count($this->cc); $i++) {
if(!$this->smtp->Recipient($this->cc[$i][0])) {
$bad_rcpt[] = $this->cc[$i][0];
}
}
for($i = 0; $i < count($this->bcc); $i++) {
if(!$this->smtp->Recipient($this->bcc[$i][0])) {
$bad_rcpt[] = $this->bcc[$i][0];
/* Build recipient list */
$all_recipients = array_map(
create_function('$a', 'return $a[0];'),
array_merge($this->to, $this->cc, $this->bcc)
);
/* Attempt to add all recipients (to, cc, and bcc) */
$this->SmtpSend_AddRecipients($all_recipients, $bad_rcpt, $was_throttled, $throttle_total);
// If the attempt failed and it looked like a throttle, split the list into smaller 'buckets'
// and then send each bucket individually. We figure out the size of each bucket based on the
// number of recipients that were accepted before we recieved the throttle 45X error.
if ($was_throttled && $this->smtp->Reset()) {
// Split recipients into roughly equal buckets
for ($i = 0; $i < count($all_recipients); $i++) {
$buckets[$i] = array_splice($all_recipients, 0, $throttle_total);
}
foreach ($buckets as $bucket) {
if (!$this->smtp->Mail($smtp_from)) {
$this->SetError($this->Lang('from_failed') . $smtp_from);
$this->smtp->Reset();
return false;
}
if(count($bad_rcpt) > 0) { // Create error message
for($i = 0; $i < count($bad_rcpt); $i++) {
if($i != 0) {
$error .= ', ';
if (!$this->SmtpSend_AddRecipients($bucket, $bad_rcpt, $was_throttled)) {
if (!$was_throttled && !count($bad_rcpt)) {
$this->SetError($this->Lang('recipients_failed') . join(', ', $bucket));
$this->smtp->Reset();
return false;
}
}
if (count($bad_rcpt) > 0) { // Create error message
$this->SetError('Error Unknown: ' . $this->Lang('recipients_failed') . join(', ', $bad_rcpt));
$this->smtp->Reset();
return false;
}
if (!$this->smtp->Data($header . $body)) {
$this->SetError($this->Lang('data_not_accepted'));
$this->smtp->Reset();
return false;
}
$this->smtp->Reset();
}
$error .= $bad_rcpt[$i];
if ($this->SMTPKeepAlive == true) {
$this->smtp->Reset();
} else {
$this->SmtpClose();
}
$error = $this->Lang('recipients_failed') . $error;
$this->SetError($error);
} else { // No problems adding recipients - proceed normally
if (count($bad_rcpt) > 0) { // Create error message
$this->SetError('Unknown Error: ' . $this->Lang('recipients_failed') . join(', ', $bad_rcpt));
$this->smtp->Reset();
return false;
}
if(!$this->smtp->Data($header . $body)) {
if (!$this->smtp->Data($header . $body)) {
$this->SetError($this->Lang('data_not_accepted'));
$this->smtp->Reset();
return false;
}
if($this->SMTPKeepAlive == true) {
if ($this->SMTPKeepAlive == true) {
$this->smtp->Reset();
} else {
$this->SmtpClose();
}
return true;
}
}
/**
* Initiates a connection to an SMTP server.

View File

@ -90,6 +90,17 @@ class SMTP {
$this->do_debug = 0;
}
/**
* Returns the last error emitted by the SMTP server. This
* is reset to null on each new command call.
*
* @access public
* @return Array containing error message and code or NULL
*/
public function getLastError() {
return $this->error;
}
/*************************************************************
* CONNECTION FUNCTIONS *
***********************************************************/
@ -181,7 +192,7 @@ class SMTP {
return false;
}
fputs($this->smtp_conn,"STARTTLS" . $this->CRLF);
$this->client_send("STARTTLS" . $extra . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply,0,3);
@ -217,7 +228,7 @@ class SMTP {
*/
public function Authenticate($username, $password) {
// Start authentication
fputs($this->smtp_conn,"AUTH LOGIN" . $this->CRLF);
$this->client_send("AUTH LOGIN" . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply,0,3);
@ -235,7 +246,7 @@ class SMTP {
}
// Send encoded username
fputs($this->smtp_conn, base64_encode($username) . $this->CRLF);
$this->client_send(base64_encode($username) . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply,0,3);
@ -253,7 +264,7 @@ class SMTP {
}
// Send encoded password
fputs($this->smtp_conn, base64_encode($password) . $this->CRLF);
$this->client_send(base64_encode($password) . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply,0,3);
@ -345,7 +356,7 @@ class SMTP {
return false;
}
fputs($this->smtp_conn,"DATA" . $this->CRLF);
$this->client_send("DATA" . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply,0,3);
@ -435,13 +446,13 @@ class SMTP {
$line_out = "." . $line_out;
}
}
fputs($this->smtp_conn,$line_out . $this->CRLF);
$this->client_send($line_out . $this->CRLF);
}
}
// ok all the message data has been sent so lets get this
// over with aleady
fputs($this->smtp_conn, $this->CRLF . "." . $this->CRLF);
$this->client_send($this->CRLF . "." . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply,0,3);
@ -489,7 +500,7 @@ class SMTP {
return false;
}
fputs($this->smtp_conn,"EXPN " . $name . $this->CRLF);
$this->client_send("EXPN " . $name . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply,0,3);
@ -564,7 +575,7 @@ class SMTP {
* @return bool
*/
private function SendHello($hello, $host) {
fputs($this->smtp_conn, $hello . " " . $host . $this->CRLF);
$this->client_send($hello . " " . $host . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply,0,3);
@ -619,7 +630,7 @@ class SMTP {
$extra = " " . $keyword;
}
fputs($this->smtp_conn,"HELP" . $extra . $this->CRLF);
$this->client_send("HELP" . $extra . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply,0,3);
@ -667,7 +678,7 @@ class SMTP {
}
$useVerp = ($this->do_verp ? "XVERP" : "");
fputs($this->smtp_conn,"MAIL FROM:<" . $from . ">" . $useVerp . $this->CRLF);
$this->client_send("MAIL FROM:<" . $from . ">" . $useVerp . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply,0,3);
@ -709,7 +720,7 @@ class SMTP {
return false;
}
fputs($this->smtp_conn,"NOOP" . $this->CRLF);
$this->client_send("NOOP" . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply,0,3);
@ -753,7 +764,7 @@ class SMTP {
}
// send the quit command to the server
fputs($this->smtp_conn,"quit" . $this->CRLF);
$this->client_send("quit" . $this->CRLF);
// get any good-bye messages
$byemsg = $this->get_lines();
@ -806,7 +817,7 @@ class SMTP {
return false;
}
fputs($this->smtp_conn,"RCPT TO:<" . $to . ">" . $this->CRLF);
$this->client_send("RCPT TO:<" . $to . ">" . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply,0,3);
@ -850,7 +861,7 @@ class SMTP {
return false;
}
fputs($this->smtp_conn,"RSET" . $this->CRLF);
$this->client_send("RSET" . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply,0,3);
@ -899,7 +910,7 @@ class SMTP {
return false;
}
fputs($this->smtp_conn,"SEND FROM:" . $from . $this->CRLF);
$this->client_send("SEND FROM:" . $from . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply,0,3);
@ -947,7 +958,7 @@ class SMTP {
return false;
}
fputs($this->smtp_conn,"SAML FROM:" . $from . $this->CRLF);
$this->client_send("SAML FROM:" . $from . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply,0,3);
@ -995,7 +1006,7 @@ class SMTP {
return false;
}
fputs($this->smtp_conn,"SOML FROM:" . $from . $this->CRLF);
$this->client_send("SOML FROM:" . $from . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply,0,3);
@ -1062,7 +1073,7 @@ class SMTP {
return false;
}
fputs($this->smtp_conn,"VRFY " . $name . $this->CRLF);
$this->client_send("VRFY " . $name . $this->CRLF);
$rply = $this->get_lines();
$code = substr($rply,0,3);
@ -1085,6 +1096,19 @@ class SMTP {
return $rply;
}
/**
* Sends data to the server
*
* @access public
* @return Integer number of bytes sent to the server or FALSE on error
*/
public function client_send($data) {
if ($this->do_debug >= 1) {
echo "CLIENT -> SMTP: $data";
}
return fputs($this->smtp_conn, $data);
}
/*******************************************************************
* INTERNAL FUNCTIONS *
******************************************************************/