ver saber origen internet headers encabezados encabezado electronico correo como cabeceras analizar php encoding mime email-headers

php - saber - encabezados en gmail



El correo electrónico de PHP ha roto la codificación del encabezado del asunto (4)

TL; DR

$preferences = [''input-charset'' => ''UTF-8'', ''output-charset'' => ''UTF-8'']; $encoded_subject = iconv_mime_encode(''Subject'', $subject, $preferences); $encoded_subject = substr($encoded_subject, strlen(''Subject: '')); mail($to, $encoded_subject, $message, $headers);

o

mb_internal_encoding(''UTF-8''); $encoded_subject = mb_encode_mimeheader($subject, ''UTF-8'', ''B'', "/r/n", strlen(''Subject: '')); mail($to, $encoded_subject, $message, $headers);

Problema y solución

Los Content-Type y Content-Transfer-Encoding solo se aplican al cuerpo de su mensaje. Para los encabezados, existe un mecanismo para especificar su codificación especificada en RFC 2047 .

Debería codificar su Subject través de iconv_mime_encode() , que existe a partir de PHP 5:

$preferences = ["input-charset" => "UTF-8", "output-charset" => "UTF-8"]; $encoded_subject = iconv_mime_encode("Subject", $subject, $preferences);

Cambia input-charset para que coincida con la codificación de tu string $subject . Debe dejar output-charset como UTF-8 . Antes de PHP 5.4, use array() lugar de [] .

Ahora $encoded_subject es (sin trailing newline)

Subject: =?UTF-8?B?VmVyeSBsb25nIHRleHQgY29udGFpbmluZyBzcGVjaWFsIGM=?= =?UTF-8?B?aGFyYWN0ZXJzIGxpa2UgxJvFocSNxZnFvsO9w6HDrcOpPD4/PSsqIHA=?= =?UTF-8?B?cm9kdWNlcyBzZXZlcmFsIGVuY29kZWQtd29yZHMsIHNwYW5uaW5nIG0=?= =?UTF-8?B?dWx0aXBsZSBsaW5lcw==?=

para $subject contiene:

Very long text containing special characters like ěščřžýáíé<>?=+* produces several encoded-words, spanning multiple lines

¿Como funciona?

La función iconv_mime_encode() divide el texto, codifica cada pieza por separado en un símbolo <encoded-word> y folds el espacio en blanco entre ellos. La palabra codificada es =?<charset>?<encoding>?<encoded-text>?= Encoded =?<charset>?<encoding>?<encoded-text>?= Donde:

Puede decodificar =?CP1250?B?QWhvaiwgc3bsdGU=?= En la cadena UTF-8 Ahoj, světe ( Hello, world en checo) a través de iconv("CP1250", "UTF-8", base64_decode("QWhvaiwgc3bsdGU=")) o directamente a través de iconv_mime_decode("=?CP1250?B?QWhvaiwgc3bsdGU=?=", 0, "UTF-8") .

La codificación en palabras codificadas es más complicada, porque la especificación requiere que cada token de palabra codificada tenga como máximo 75 bytes y cada línea que contenga cualquier token de palabra codificada debe tener como máximo 76 bytes de longitud (incluido el espacio en blanco al comienzo de una línea de continuación) ) No implemente la codificación usted mismo. Todo lo que necesitas saber es que iconv_mime_encode() respeta la especificación.

Interesante lectura relacionada es el artículo de Wikipedia Unicode y el correo electrónico .

Alternativas

Una opción rudimentaria es usar solo un conjunto restringido de caracteres. ASCII está garantizado para funcionar. ISO Latin America 1 (ISO-8859-1), como se sugirió user2250504 , probablemente también funcionará, porque a menudo se usa como reserva cuando no se especifica ninguna codificación. Pero esos juegos de caracteres son muy pequeños y es probable que no puedas codificar todos los caracteres que desees. Además, los RFC no dicen nada sobre si Latin 1 debería funcionar o no.

También puede usar mb_encode_mimeheader() , como respondió Paul Norman , pero es fácil usarlo incorrectamente.

  1. Debe usar mb_internal_encoding() para establecer la codificación usada internamente de las funciones mbstring. Las funciones mb_* esperan que las cadenas de entrada estén en esta codificación. Cuidado: el segundo parámetro de mb_encode_mimeheader() no tiene nada que ver con la cadena de entrada (a pesar de lo que dice el manual). Corresponde al <charset> en la palabra codificada (ver ¿Cómo funciona? Arriba). La cadena de entrada se codifica a partir de la codificación interna a esta antes de pasarse a la codificación B o Q.

    La configuración de la codificación interna podría no ser necesaria desde PHP 5.6, ya que la opción de configuración subyacente mbstring.internal_encoding había quedado en desuso en favor de la opción default_charset , que se configuró en UTF-8 de forma predeterminada, ya que. Tenga en cuenta que esto es solo un defecto y puede ser inapropiado confiar en los valores predeterminados de su código.

  2. Debe incluir el nombre del encabezado y dos puntos en la cadena de entrada. ¡El RFC impone un límite fuerte en la longitud de línea y también debe mantenerse para la primera línea! Una alternativa es jugar con el quinto parámetro ( $indent , el último a partir de septiembre de 2015), pero esto es aún menos conveniente.

  3. La implementación podría tener errores. Incluso si se usa correctamente, es posible que obtenga una salida interrumpida. Al menos esto es lo que dicen muchos comentarios en la página del manual. No he logrado encontrar ningún problema, pero sé que la implementación de palabras codificadas es complicada. Si encuentra errores potenciales o reales en mb_encode_mimeheader() o iconv_mime_encode() , hágamelo saber en los comentarios.

También hay al menos una ventaja al usar mb_encode_mimeheader() : no siempre codifica todos los contenidos del encabezado, lo que ahorra espacio y deja el texto legible para el ser humano. La codificación se requiere solo para las partes que no son ASCII. La salida análoga al ejemplo de iconv_mime_encode() anterior es:

Subject: Very long text containing special characters like =?UTF-8?B?xJvFocSNxZnFvsO9w6HDrcOpPD4/PSsqIHByb2R1Y2VzIHNldmVyYWwgZW5j?= =?UTF-8?B?b2RlZC13b3Jkcywgc3Bhbm5pbmcgbXVsdGlwbGUgbGluZXM=?=

Ejemplo de uso de mb_encode_mimeheader() :

mb_internal_encoding(''UTF-8''); $encoded_subject = mb_encode_mimeheader("Subject: $subject", ''UTF-8''); $encoded_subject = substr($encoded_subject, strlen(''Subject: '')); mail($to, $encoded_subject, $message, $headers);

Esta es una alternativa al fragmento en TL; DR en la parte superior de esta publicación. En lugar de simplemente reservar el espacio para el Subject: en realidad lo coloca allí y luego lo elimina para poder usarlo con la estúpida interfaz del mail() .

Si le gustan las funciones mbstring mejor que las iconv, puede usar mb_send_mail() . Utiliza mail() internamente, pero codifica el asunto y el cuerpo del mensaje automáticamente. De nuevo, use con cuidado .

Los encabezados que no sean el Sujeto necesitan un tratamiento diferente

Tenga en cuenta que no debe asumir que la codificación de todo el contenido de un encabezado está bien para todos los encabezados que pueden contener caracteres que no sean ASCII. Por ejemplo, From, To, Cc, Bcc y Reply-To pueden contener nombres para las direcciones que contienen, pero solo los nombres pueden estar codificados, no las direcciones. La razón es que el token <encoded-word> puede reemplazar solo tokens <text> , <ctext> y <word> , y solo bajo ciertas circunstancias (ver §5 de RFC 2047 ).

La codificación de texto no ASCII en otros encabezados es una pregunta relacionada pero diferente. Si desea saber más sobre este tema, busque. Si no encuentra respuesta, haga otra pregunta y apúnteme a ella en los comentarios.

Mi script PHP envía correos electrónicos a los usuarios y cuando el correo electrónico llega a sus buzones de correo, la línea de asunto ( $subject ) tiene caracteres como a^£ añadidos al final del texto del tema. Esto es obviamente un problema de codificación. El contenido del mensaje de correo electrónico está bien, solo el asunto está roto.

He buscado por todas partes pero no puedo encontrar cómo codificar mi tema correctamente .

Este es mi encabezado Tenga en cuenta que estoy usando Content-Type con charset=utf-8 y Content-Transfer-Encoding: 8bit .

//set all necessary headers $headers = "From: $sender_name<$from>/n"; $headers .= "Reply-To: $sender_name<$from>/n"; $headers .= "X-Sender: $sender_name<$from>/n"; $headers .= "X-Mailer: PHP4/n"; //mailer $headers .= "X-Priority: 3/n"; //1 UrgentMessage, 3 Normal $headers .= "MIME-Version: 1.0/n"; $headers .= "X-MSMail-Priority: High/n"; $headers .= "Importance: 3/n"; $headers .= "Date: $date/n"; $headers .= "Delivered-to: $to/n"; $headers .= "Return-Path: $sender_name<$from>/n"; $headers .= "Envelope-from: $sender_name<$from>/n"; $headers .= "Content-Transfer-Encoding: 8bit/n"; $headers .= "Content-Type: text/plain; charset=UTF-8/n";


Guarde el archivo php con el juego de caracteres apropiado.

En mi caso, en Sublime Text, utilicé la siguiente opción:

Archivo> Guardar con codificación> Western (ISO-8859-1) [para portugués de Brasil]

Al hacer esto, no necesita usar ningún comando.


mb_encode_mimeheader() para cadenas UTF-8 puede ser útil aquí, por ejemplo

$subject = mb_encode_mimeheader($subjectText,"UTF-8");


Actualización Para una respuesta más práctica y actualizada, eche un vistazo a la respuesta de Palec .

La codificación de caracteres especificada en Content-Type solo describe la codificación de caracteres del cuerpo del mensaje, pero no el encabezado. Necesita utilizar la sintaxis de palabra codificada con la codificación imprimible entre comillas o la codificación Base64 :

encoded-word = "=?" charset "?" encoding "?" encoded-text "?="

Puede usar imap_8bit para la codificación imprimible entre comillas y base64_encode para la codificación Base64:

"Subject: =?UTF-8?B?".base64_encode($subject)."?=" "Subject: =?UTF-8?Q?".imap_8bit($subject)."?="