PHP的mail()函数附件是否在Windows上有点破碎?

时间:2011-09-23 01:31:28

标签: php performance email attachment

我的客户今天记录了一张票据,报告说当我尝试发送附件时,PHP的mail()功能在我的一个Windows 2003 Server盒子上超时了。

经过调查,我能够重现他的问题。包含30-60Kb大小的小附件的消息需要15-20秒才能由mail()函数处理。较大的附件大约360-500Kb所花费的时间超过允许的最大脚本执行时间(90秒)。

我能够在两台不同的Windows 2003服务器和一台Windows 2008R2服务器上重现该问题。我还尝试了三个不同版本的PHP(5.2.14,5.2.17和5.3.6 - 所有32位和所有非线程安全版本,根据Microsoft在Windows上运行PHP的建议)。

在所有情况下,邮件都是通过SMTP发送的(即不使用sendmail实现)。我尝试了三种不同的SMTP方案:

  • 直接发送到我们的SMTP智能主机群集(运行exim)
  • 通过本地IIS SMTP服务传递,该服务转发到我们的智能主机
  • 通过本地IIS SMTP服务传递,但使用MX查找和直接传递

无论如何,发送附件仍然不是最理想的,这意味着问题无法固定在慢速继电器上。

然后我在CentOS服务器上运行了相同的代码,这些代码没有出现任何这些问题,mail()函数几乎立即返回。但是,这些服务器上的PHP配置为使用sendmail

然后我决定使用PHP源代码来查找mail()函数的实现情况,并在ext/standard/mail.c中发现此代码:

if (!sendmail_path) {
#if (defined PHP_WIN32 || defined NETWARE)
    /* handle old style win smtp sending */
    if (TSendMail(INI_STR("SMTP"), &tsm_err, &tsm_errmsg, headers, subject, to, message, NULL, NULL, NULL TSRMLS_CC) == FAILURE) {
        if (tsm_errmsg) {
            php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", tsm_errmsg);
            efree(tsm_errmsg);
        } else {
            php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", GetSMErrorText(tsm_err));
    }
        return 0;
    }
    return 1;
#else
    return 0;
#endif

TSendMail()在另一个源文件(win32/sendmail.c)中实现。最终,发送到SMTP服务器的所有数据似乎都通过Post()中名为sendmail.c的函数同步传递,如下所示:

static int Post(LPCSTR msg)
{
    int len = strlen(msg);
    int slen;
    int index = 0;

    while (len > 0) {
        if ((slen = send(sc, msg + index, len, 0)) < 1)
            return (FAILED_TO_SEND);
        len -= slen;
        index += slen;
    }
    return (SUCCESS);
}

send()函数是winsock2函数。

我想知道缓冲区大小(根据下面的知识库文章,默认为8K)或缺乏调优对于大量数据有一些影响。没有调用setsockopt()指定缓冲区大小或任何其他选项来优化对send()的调用。

使用SMTP传递的Windows上的mail()功能可能不会用于发送大型电子邮件吗?

我有兴趣知道是否有其他人看过这段代码或经历过同样的事情。

  

Design issues - Sending small data segments over TCP with Winsock

为了清楚起见,我们现在已经为客户(SwiftMailer)提供了替代解决方案,因此这不是为了获得替代方案的建议。

1 个答案:

答案 0 :(得分:1)

我的想法是在Windows上使用http://glob.com.au/sendmail/和PEAR Mail类:http://pear.php.net/package/Mail。这可能是您遇到的延迟的解决方法。我认为这将无法绕过缓冲区,但我认为值得一试。

另外,我从未使用它,但我听说过SwiftMailer的好消息:http://swiftmailer.org/