一周后PHP脚本失败,出现SMTP错误10055

时间:2016-08-18 11:37:18

标签: php apache email phpmailer

我有一个REST PHP脚本(在Windows服务器2012 R2上的Apache上运行),使用PHPMailer通过另一台机器上的Postfix SMTP服务器发送邮件。

邮件工作完美无缺,直到大约一周(50-100封电子邮件)邮件突然停止工作。发送邮件的任何进一步尝试都会导致SMTP错误:

  

无法连接到服务器:无法执行对套接字的操作,因为系统缺少足够的缓冲区空间或队列已满。 (10055)

查看Postfix服务器日志,Apache服务器日志和PHP日志不会引起任何兴趣,也不会弹出错误。使用邮件服务器通过其他方式发送邮件即使在同一台机器上也能正常工作。此时,我们重新启动运行PHP的Apache服务器,使所有内容再次运行一周。

从我能够找到的,这个错误是机器上的TCP缓冲区已满的结果。这通常是因为连接打开然后不再关闭。除PHPMailer外,PHP脚本不进行任何网络通信。

所以我的问题是,如果我需要处理某种连接处理,当我完成发送邮件时,我是否必须在PHPMailer中关闭句柄或类似处理(某些事情并非如此)如例所示)?在某处进行配置更改?我是一名C ++程序员,对PHP的内部工作知之甚少。

以下是该脚本的相关部分:

<?php

require '../../phpmailer/PHPMailerAutoload.php';

abstract class Status {
    const SUCCESS = 0;
    const FAILED = 1;
    const ABORTED = 2;
    const INVALID = 3;
}

class JobController extends MyController
{
    public function postAction($request) {
        // Do stuff
    }

    public function putAction($request) {
        // Do stuff
    }

    public function deleteAction($request) {
        // Make sure there is a job id at the end of the url
        if (count($request->url_elements) != 3)
            return new Result(404, array('message' => 'Invalid command'));

        // Initialize the session and check if it is set
        if (!$this->mySessionStart())
            return new Result(401, array('message' => 'Not logged in'));

        // Check if the mirror parameter exists
        $mirror = null;
        if (isset($request->parameters['mirror']))
            $mirror = base64_decode($request->parameters['mirror']);

        // Check that status parameter exists
        if (!isset($request->parameters['result']))
            return new Result(400, array('message' => 'Missing result parameter'));

        // Parse status parameter
        if (strcasecmp($request->parameters['result'], 'success') === 0)
            $status = Status::SUCCESS;
        else if (strcasecmp($request->parameters['result'], 'failed') === 0)
            $status = Status::FAILED;
        else if (strcasecmp($request->parameters['result'], 'aborted') === 0)
            $status = Status::ABORTED;
        else
            $status = Status::INVALID;

        // Check that the status value is valid
        if ($status === Status::INVALID)
            return new Result(400, array('message' => 'Invalid result value'));

        // Check that download parameter exists if status is 'success'
        if (($status == Status::SUCCESS) && !isset($request->parameters['download']))
            return new Result(400, array('message' => 'Missing download parameter'));

        // Check that reason parameter exists if status is 'failed'
        if (($status == Status::FAILED) && !isset($request->parameters['reason']))
            return new Result(400, array('message' => 'Missing reason parameter'));

        $jobid = $request->url_elements[2];
        $filepath = ACTIVE_JOBS_PATH . $jobid . '.json';

        if (!file_exists($filepath))
            return new Result(404, array('message' => 'Unknown job'));

        $templates = __DIR__ . '\\..\\templates\\';

        if ($status === Status::SUCCESS) {
            $str = file_get_contents($filepath);
            $json = $this->decodeJson($str);
            $email_addr = $json['userEmail'];
            $name = $json['jobName'];
            $path = base64_decode($request->parameters['download']);

            if (Empty($name))
                $name = 'Unnamed';

            $raw_text = "Your volume export $name is finished and can be downloaded here:\r\n$path";
            $template_name = (Empty($mirror) ? 'success_name.html' : 'success_name_mirror.html');

            // If FTP then override the name with the ftp template.
            if (substr($path, 0, 4) == 'ftp:')
                $template_name = 'success_name_ftp.html';

            $html_text = file_get_contents($templates . $template_name);
            $html_text = str_replace(array("%name%", "%path%", "%mirror%", "%server%"), array($name, $path, $mirror, SERVER_PATH), $html_text);

            $mail = $this->createMail($email_addr, "Your volume extraction job is complete", $html_text, $raw_text);

            if(!$mail->send())
                return new Result(500, array('message' => 'failed to send mail', 'mail error' => $mail->ErrorInfo));

            // Delete job first when we have managed to send a mail correctly
            unlink($filepath);
        }
        elseif ($status === Status::FAILED) {
            $str = file_get_contents($filepath);
            $json = $this->decodeJson($str);
            $email_addr = $json['userEmail'];
            $name = $json['jobName'];
            $msg = base64_decode($request->parameters['reason']);

            if (Empty($name))
                $name = 'Unnamed';

            $raw_text = "Your volume export $name has failed and the reason given was:\r\n$msg";

            $msg = str_ireplace("\r\n", "<br>", $msg);  // Replace any newlines with <br> tags
            $msg = str_ireplace("\n", "<br>", $msg);

            $html_text = file_get_contents($templates . 'fail_name.html');
            $html_text = str_replace(array("%name%", "%msg%", "%server%"), array($name, $msg, SERVER_PATH), $html_text);

            $mail = $this->createMail($email_addr, "Your volume extraction job has failed", $html_text, $raw_text);

            if(!$mail->send())
                return new Result(500, array('message' => 'failed to send mail', 'mail error' => $mail->ErrorInfo));

            // Delete job first when we have managed to send a mail correctly
            unlink($filepath);
        }
        elseif ($status === Status::ABORTED) {
            rename($filepath, JOBS_PATH . $jobid . '.json');
        }

        return new Result(200, array('jobId' => $jobid));
    }

    private function createMail($to, $subject, $body_html, $alt_body) {
        $settings = parse_ini_file('..\\..\\settings.ini');

        $mail = new PHPMailer;

        $mail->CharSet = 'UTF-8';
        $mail->isSMTP();                                // Set mailer to use SMTP
        $mail->Host = $settings['MAIL_HOST'];           // Specify main and backup SMTP servers
        $mail->SMTPAuth = true;                         // Enable SMTP authentication
        $mail->Username = $settings['MAIL_USER'];       // SMTP username
        $mail->Password = $settings['MAIL_PASS'];       // SMTP password
        $mail->SMTPSecure = $settings['MAIL_SECURE'];   // Enable TLS encryption, `ssl` also accepted
        $mail->Port = $settings['MAIL_PORT'];           // TCP port to connect to

        $mail->From = 'example@example.com';
        $mail->FromName = 'Example';
        $mail->addAddress($to);
        $mail->addReplyTo('noreply@example.com');

        $mail->isHTML(true);                        // Set email format to HTML

        $mail->Subject = $subject;
        $mail->Body    = $body_html;
        $mail->AltBody = $alt_body;

        return $mail;
    }

    private function decodeJson($str) {
        $char = json_decode('"\uFEFF"');    // UTF-8 byte order mark
        return json_decode(trim(str_replace($char, '', $str)), true);   // Replace BOM if needed
    }
}

?>

0 个答案:

没有答案