Не работает ли поддержка PHP-вложений функции mail () в Windows?

Сегодня заказчик зарегистрировал у меня билет, в котором сообщалось, что функция PHP mail () отключала от него тайм-аут на одном из наших ящиков Windows 2003 Server при попытке отправить вложения. .

После исследования я смог воспроизвести его проблему. Сообщения, содержащие небольшие вложения размером около 30-60 КБ, обрабатывались функцией mail () за 15-20 секунд. Вложения большего размера, размером около 360-500 КБ, занимали больше времени, чем разрешено максимально допустимое время выполнения скрипта (90 секунд).

Мне удалось воспроизвести проблему на двух разных серверах Windows 2003 и сервере Windows 2008R2. Я также пробовал три разные версии PHP (5.2.14, 5.2.17 и 5.3.6 - все 32-битные и все небезопасные сборки в соответствии с рекомендациями Microsoft по запуску PHP в Windows).

Во всех случаях почта отправлялась через SMTP (т.е. без использования sendmail). Я пробовал три разных сценария SMTP:

  • Доставка напрямую в наш SMTP-кластер smarthost (работает exim)
  • Доставка через локальную службу IIS SMTP, которая ретранслирует на наши smarthosts.
  • Доставка через локальную службу IIS SMTP, но с поиском MX и прямым delivery

Несмотря на вышесказанное, отправка вложений все еще была неоптимальной, что означает, что проблема не может быть связана с медленным реле.

Затем я запустил тот же код на наших серверах 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 .

Мне интересно, влияет ли размер буфера (8 КБ по умолчанию в соответствии со статьей базы знаний ниже) или отсутствие настройки на большие объемы данных. Нет никаких вызовов setsockopt () для указания размера буфера или любых других параметров для оптимизации вызовов send () .

Возможно, функция mail () в Windows с использованием доставки SMTP не предназначена для использования для отправки больших писем?

Мне было бы интересно узнать, смотрел ли кто-нибудь еще на этот код или испытал то же самое.

Проблемы проектирования - отправка небольших сегментов данных по TCP с помощью Winsock

Чтобы было ясно, у нас уже есть альтернативное решение для клиента (SwiftMailer), поэтому речь не идет о получении рекомендаций по альтернативам.

6
задан Kev 23 September 2011 в 07:45
поделиться