2011-09-23 14 views
6

Tuve un boleto registrado por un cliente hoy informando que la función mail() de PHP le estaba agotando el tiempo en uno de nuestros cuadros de Windows 2003 Server cuando intentaba enviar archivos adjuntos.¿El soporte de la función de correo de PHP() es un poco defectuoso en Windows?

Al investigar, pude reproducir su problema. Los mensajes que contenían archivos adjuntos pequeños con un tamaño aproximado de 30-60 Kb tardaban de 15 a 20 segundos en procesarse con la función mail(). Los archivos adjuntos más grandes de alrededor de 360-500 Kb tardaban más que el tiempo máximo de ejecución del script permitido (90 segundos).

que era capaz de reproducir el problema en dos servidores diferentes de Windows 2003 y un servidor Windows 2008R2. También probé tres versiones diferentes de PHP (5.2.14, 5.2.17 y 5.3.6 - todas las compilaciones de 32 bit y todas las que no son de rosca según las recomendaciones de Microsoft para ejecutar PHP en Windows).

en todos los casos de correo estaba siendo enviado a través de SMTP (es decir, no utilizando una aplicación sendmail). Probé tres diferentes escenarios SMTP:

  • entrega directamente a nuestro cluster SMTP host inteligente (Exim corriendo)
  • entrega a través de local de servicio SMTP de IIS que retransmite a nuestros SmartHosts
  • entrega a través de local de servicio SMTP de IIS, pero con MX búsqueda y entrega directa

Independientemente de lo anterior, el envío de archivos adjuntos aún no era óptimo, lo que significa que el problema no se puede fijar en un relé lento.

Luego ejecuté el mismo código en nuestros servidores CentOS que no presentaban ninguno de estos problemas, la función mail() se devolvió casi de inmediato. Sin embargo, PHP en estos servidores está configurado para usar sendmail.

Entonces decidí spelunk el código fuente PHP para averiguar lo que la implementación de la función mail() parecía y descubrió este código en 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() se implementa en otro archivo de origen (win32/sendmail.c). En última instancia, todos los datos enviados a un servidor SMTP parece estar pasado de forma sincrónica a través de una función llamada Post()sendmail.c en la que se parece:

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); 
} 

La función es una función send()winsock2.

Me pregunto si el tamaño del búfer (8K es el valor predeterminado de acuerdo con el artículo de KB a continuación) o la falta de sintonía está teniendo algún impacto aquí para obtener grandes cantidades de datos. No hay llamadas al setsockopt() para especificar un tamaño de búfer u otras opciones para optimizar las llamadas al send().

Tal vez la función mail() sobre el uso de la entrega SMTP de Windows no está destinado a ser utilizado para el envío de grandes mensajes de correo electrónico?

Me interesaría saber si alguien más ha mirado este código o experimentado lo mismo.

Design issues - Sending small data segments over TCP with Winsock

Para que quede claro, que ya tienen una solución alternativa para el cliente (SwiftMailer) en su lugar ahora para que esto no se trata de obtener recomendaciones de alternativas.

+1

No es frecuente ver a una pregunta de a) un administrador, y b) una persona con una gran cantidad de repeticiones. Debe ser NP-Hard ...: P –

+0

Me pregunto si una recompensa está en orden en este caso. –

+0

mail() tiene poco poder, nunca lo use para nada que no sea súper básico. Creo que el manual alude a esto –

Respuesta

1

Mis pensamientos utilizarían http://glob.com.au/sendmail/ en Windows con la clase PEAR Mail: http://pear.php.net/package/Mail. Esto podría ser una solución para la latencia que está experimentando. Estoy pensando que esto no será capaz de eludir el buffer, pero creo que valdría la pena intentarlo.

Además, nunca lo han utilizado, pero he oído cosas buenas sobre SwiftMailer: http://swiftmailer.org/

+0

Está bien, ya he recomendado SwiftMailer, que es bastante bueno. – Kev

Cuestiones relacionadas