Ver índice
Formatos MIME

        Ocultar índice  

   Índice de contenidos
   Instalación en Windows
   Instalación en Ubuntu
   Servidores seguros
   Páginas dinámicas
   Sintaxis básica
   Operaciones
   Arrays
   Formatos de presentación
   Operadores
   Bucles
   Extraer y ord. información
   Funciones
   Ficheros externos
   Imágenes dinámicas
   Gestión de directorios
   Cookies y sesiones
   Clases y objetos
   Ficheros en formato PDF
   Bases de datos MySQL
   PHP y XML
   PDO - Bases SQLite / MySQL
   MySQL a traves de misqli
   Algo de JavaScript y AJAX


Funciones PHP requeridas para el envío de mensajes

Podrás ver a lo largo de los ejemplos de envío de mensajes de correo electrónico algunas funciones raras que vamos a comentar seguidamente:

uniqid(prefijo,booleano)

Genera un identificador único basado en la hora actual del sistema, expresada en microsegundos y con una longitud de 13 caracteres. El parámetro prefijo permite establecer una cadena o número (puede ser una cadena vacía) que se antepone al identificador generado por la función. Opcionalmente permite el segundo parámetro booleano que debe ser un valor booleano (TRUE ó FALSE) o también 0 ó 1. Cuando este parámetro es TRUE añade al final de la cadena generada anteriormente otra subcadena numérica -generada aleatoriamente- de nueve dígitos, que refuerza la unicidad del identificador.

preg_replace(busca, reemplaza, cadena)

Busca en la cadena especificada en el parámetro cadena (que puede ser una cadena o una variable que contenga una cadena) las subcadenas especificadas en busca (recuerda que debe llevar delante y detrás un carácter delimitador tal como puedes ver en las expresiones regulares) y sustituye esas subcadenas por el contenido del parámetro reemplaza. Devuelve la cadena modificada.

strip_tags(cadena, excepciones)

Suprime todas las etiquetas HTML contenidas en cadena salvo las que se indiquen en excepciones. Por ejemplo: strip_tags($cadena, '<i><u><b>') eliminaría todas las etiquetas HTML, salvo las indicadas aquí y sus correspondientes cierres. Si no se especifican excepciones elimina todas las etiquetas.

base64_encode(cadena)

Devuelve una cadena codificada en base64. Esta codificación se hace para permitir que las informaciones binarias puedan ser correctamente manipuladas por sistemas que no generan correctamente los 8 bits, tal como ocurre frecuentemente en los cuerpos de los mensajes de correo electrónico.

base64_decode(cadena)

Realiza el proceso inverso a la anterior. Decodifica una cadena previamente codificada en base64.

chunk_split(cadena, longitud, separador)

Devuelve una cadena obtenida al insertar en la cadena especificada -a intervalos del número de caracteres especificados en el parámetro numérico longitud- el contenido de una subcadena indicada en el parámetro separador. Por defecto -cuando no se especifican los parámetros- longitud es igual a 76 caracteres y el separador es la cadena \r\n (retorno y salto de línea).

Esta función se utiliza para convertir al formato especificado en la RFC 2045 (especificación para MIME) las cadenas obtenidas por base64_encode. Es el formato habitual de los ficheros adjuntos de los e-mail.

Formato de los mensajes de correo electrónico

En la página anterior hemos hablado acerca de la manera de enviar un e-mail y veíamos la forma de insertar el cuarto parámetro de la función mail para incluir algunos elementos de los encabezados MIME. El formato de los mensajes está especificado en una serie de normas conocidas como el MIME (Multipurpose Internet Mail Extensions) en las que se establecen los contenidos y la sintaxis de las diferentes partes de un mensaje.

Recordemos que la función

mail(destinatario, asunto, mensaje, cabecera)

tiene cuatro parámetros y que las especificaciones del MIME aluden a los dos últimos, es decir a mensaje (el cuerpo del mensaje) y cabecera que es el encabezado del mismo. Respecto a destinatario y asunto no se requieren más comentarios que reiterar la necesidad de incluir esos valores (e-mail del destinatario y asunto) bien directamente, como parámetro en la función, o a través de una variable tal como hemos comentado en la página anterior.

Cabeceras de los mensajes

Los diferentes elementos de la cabecera de un mensaje deben insertarse siempre separados por saltos de línea bien pulsando Enter o incluyendo la secuencia \n dentro de la misma de línea. No pueden incluirse espacios, ni al comiezo de las nuevas líneas ni después de \n, y las comillas –que han de contener todo el encabezado– se abren delante del primero de ellos y no se cierran hasta después de haber escrito el último. Pueden contener lo siguiente:

Date: xxxxx

Date: debe escribirse con esta sintaxis exactamente. El parámetro xxxxx es una cadena que contendrá la fecha de envío del mensaje y que puede obtenerse a través de una de las funciones de fecha de PHP tal como puedes ver en el ejemplo.

MIME-Version: 1.0

Este elemento de la cabecera especificará la versión MIME que ha de utilizar el cliente de correo para poder interpretar adecuadamente el contenido de los mensajes.

From: remitente<e-mail>

Este elemento de la cabecera permite indicar el nombre del remitente (remitente) y su dirección e-mail siguiendo la sintaxis que se especifica. El nombre, como un elemento independiente y la dirección e-mail dentro de < >.

¡Cuidado!

No debemos poner comillas ni en el nombre del remitente, ni en la dirección e-mail, ni en la fecha, etcétera.

Respecto a Cc: y Bcc: ; Reply-To: y X-Mailer: son válidos los comentarios que hemos hecho en la página anterior.

Si no se especifica lo contrario, los mensajes se envían como texto sin formato, pero existen opciones que permiten especificar el formato que ha de tener un mensaje. La especificación de un formato obliga a incluir otro elemento en cabecera del mensaje:

Content-Type:

Este elemento debe ir seguido de la especificación en la que se indique el tipo de contenido. Tiene la sintaxis: tipo/subtipo. El MIME establece un gran variedad de opciones para este propósito. Hablaremos de dos de ellas:

Los tipos anteriores permiten enviar mensajes simples (sin ficheros adjuntos) en uno u otro formato, pero el MIME nos da opciones para insertar dentro de un mismo mensaje elementos de diferentes tipos y subtipos. Las opciones de mayor interés son las siguientes:

boundary=cadena

Dentro del encabezado y siempre en línea aparte (fíjate que en los ejemplos o está en línea aparte o aparece el \n) debemos incluir el elemento boundary= (sin símbolo de $ delante) y detrás del signo igual una cadena (en este caso entre comillas) que en principio puede ser una cadena cualquiera que no contenga espacios, aunque lo habitual es incluirla con el formato que podemos ver en los ejemplos.

El cuerpo del mensaje

En su formato más simple el cuerpo del mensaje contiene únicamente texto, pero cuando se trata de multipartes deberá contener necesariamente: los separadores de las diferentes partes, los encabezados de cada una de las partes y sus respectivos contenidos. La secuencia habría de ser de este tipo:

  ¡Cuidado!  

La inserción de ficheros adjuntos requiere que éstos estén disponibles en el servidor por lo que, antes de enviarlos, habrá que subirlos al servidor utilizando un proceso como el que hemos analizado cuando hablábamos de Transferencia de ficheros.

Las cabeceras MIME de un mensaje

Aquí tienes un ejemplo con los diferentes elementos del encabezado de un mensaje. Como ves, hemos incluido todos los elementos dentro de la función mail.

<?
mail("juan@mispruebas.as", "Cabeceras", "Prueba de cabeceras",
	"Date: 24 de Junio de 2001
MIME-Version: 1.0
From: Estudiante Perico<perico@mispruebas.as>
Cc:perico@mispruebas.as
Bcc:andres@mispruebas.as
Reply-To: perico@mispruebas.as
X-Mailer: PHP/".phpversion());
?>

Una forma un poco más depurada del script anterior podría ser esta que incluimos aquí debajo. Sus particularidades son las siguientes:

<?
# datos del mensaje
$destinatario="juan@mispruebas.as";
$titulo="Cabeceras en variables";
$mensaje="Nueva prueba de cabeceras";
$responder="andres@mispruebas.as";
$remite="andres@mispruebas.as";
$remitente="Otra vez Andres"; //sin tilde para evitar errores de servidor
# cabeceras
$cabecera ="Date: ".date("l j F Y, G:i")."\n"; 
$cabecera .="MIME-Version: 1.0\n"; 
$cabecera .="From: ".$remitente."<".$remite.">\n";
$cabecera .="Return-path: ". $remite."\n";
$cabecera .="X-Mailer: PHP/". phpversion()."\n";

if( mail($destinatario, $titulo, $mensaje,$cabecera)){
   echo "mensaje enviado";}else{print "el mensaje no ha podido enviarse";
}  
?>

Mensaje con contenido alternativo

<?
# creamos la variables "salto" para "mayor comodidad
# un salto es la secuencia retorno de carro-nueva línea
# dos saltos es algo similar pero duplicado

$UN_SALTO="\r\n";
$DOS_SALTOS="\r\n\r\n";

# creamos el remitente, etc. y también la que parte que
# contiene el código HTML del mensaje

$destinatario="juan@mispruebas.as";
$titulo="Mensaje alternativo Texto Plano - HTML ";
$mensaje="<html><head></head><body bgcolor='#ff0000'>";
$mensaje .="<font face='Arial' size=6>Prueba HTML. </font>";
$mensaje .="aquí pueden ir tildes: á, é, í, ó, ú, ñ</body></html>";
$responder="andres@mispruebas.as";
$remite="andres@mispruebas.as";
$remitente="Andres Perez y Perez";
// omitimos las tildes en encabezados para evitar errores de servidor

# creamos el separador de bloques del mensaje
# anteponiento "_separador" aunque podríamos haber puesto "tiburcio"
# generamos un identificador unico utilizando un numero aleatorio
# como "semilla" y luego lo codificamos con la función md5

$separador ="_separador".md5 (uniqid (rand())); 

# creamos la variable cabecera con los elementos
# ya utilizados en los ejemplos anteriores y ponemos al final
# de cada elemento UN SALTO DE LINEA

$cabecera = "Date: ".date("l j F Y, G:i").$UN_SALTO; 
$cabecera .="MIME-Version: 1.0\n"; 
$cabecera .="From: ".$remitente."<".$remite.">".$UN_SALTO;
$cabecera .= "Return-path: ". $remite.$UN_SALTO;
$cabecera .="Cc:perico@mispruebas.as".$UN_SALTO;
$cabecera .="Reply-To: ".$remite.$UN_SALTO;
$cabecera .="X-Mailer: PHP/". phpversion().$UN_SALTO;

# AQUÍ DEFINIMOS EL CONTENIDO MULTIPART, fíjate que lo acabamos con ";"

$cabecera .="Content-Type: multipart/alternative;".$UN_SALTO; 

# insertamos BOUNDARY (fíjate que dejo un espacio
# en BLANCO DELANTE y ponemos al FINAL los DOS SALTOS DE LINEA

$cabecera .=" boundary=$separador".$DOS_SALTOS;

# colocamos el primer separador(con los dos guiones delante)
# antes de insertar la primera parte del mensaje
# que es el texto plano para el caso de que el cliente de correo
# no soporte HTML

$texto_plano ="--$separador".$UN_SALTO; 

# especificamos el tipo de contenido y la codificación
# e inserto DOS SALTOS AL FINAL ya que ahi acaba la cabecera de esta parte
$texto_plano .="Content-Type:text/plain; charset=\"ISO-8859-1\"".$UN_SALTO; 
$texto_plano .="Content-Transfer-Encoding: 7bit".$DOS_SALTOS; 

# cambiamos las etiquetas "<br>" por saltos de línea
# y luego quitamos todas las etiquetas HTML del cuerpo del mensaje
# ya que el texto plano no debe llevar ese tipo de etiquetas

 $extractor= strip_tags(preg_replace("/<br>/", $UN_SALTO, $mensaje)); 

 $texto_plano .=$extractor;

# insertamos un nuevo separador para señalar el final
# de la primera parte del mensaje y el comienzo de la segunda
# en este caso ponemos UN SALTO delante del separador ya que de lo contrario
# al componer el mensaje se uniría con la cadena texto_plano anterior
# que no tiene SALTO DE LINEA AL FINAL

$texto_html =$UN_SALTO."--$separador".$UN_SALTO;

 # especificamos el encabezado HTML para el siguiente bloque
 # y ponemos en la ultima línea los DOS SALTOS DE LINEA

$texto_html .="Content-Type:text/html; charset=\"ISO-8859-1\"".$UN_SALTO; 
$texto_html .="Content-Transfer-Encoding: 7bit".$DOS_SALTOS; 
#añado la cadena que contiene el mensaje
 $texto_html .= $mensaje; 

# insertamos  SOLAMENTE un SALTO DE LINEA 
 # estamos al funal del mensaje

 $texto_html .=$UN_SALTO; 

 # unimos ambas cadenas para crear el cuerpo del mensaje

  $mensaje=$texto_plano.$texto_html;
 
 # enviamos el mensaje utilizando 

  
if( mail($destinatario, $titulo, $mensaje,$cabecera)){
	echo "mensaje enviado ";}else{print "ha habido errores en el envio";
}

?>


Mensaje con ficheros adjuntos

<?
# definimos estas variables igual que en el ejemplo anterior

$UN_SALTO="\r\n";
$DOS_SALTOS="\r\n\r\n";

#incluimos en varias, asunto, un texto en HTML
# remitente, etc. etc.

$destinatario="perico@mispruebas.as";
$titulo="Mensaje con dos fichero adjuntos";
$mensaje="<html><head></head><body bgcolor=\"#ff0000\">";
$mensaje .="<font face=\"Arial\" size=6>Prueba HTML </font>";
$mensaje .="</body></html>";
$responder="andres@mispruebas.as";
$remite="andres@mispruebas.as";
$remitente="Andres otra vez";

# definimos el separador de parte 
# con el mismo procedimiento del ejemplo anterior

$separador = "_separador_de_trozos_".md5 (uniqid (rand())); 

# insertamos los datos de la cabecera del mensaje
  
$cabecera = "Date: ".date("l j F Y, G:i").$UN_SALTO; 
$cabecera .= "MIME-Version: 1.0".$UN_SALTO; 
$cabecera .= "From: ".$remitente."<".$remite.">".$UN_SALTO;
$cabecera .= "Return-path: ". $remite.$UN_SALTO;
$cabecera .= "Reply-To: ".$remite.$UN_SALTO;
$cabecera .="X-Mailer: PHP/". phpversion().$UN_SALTO;

# especificamos el tipo de contenido mutipart/mixed
# ya que ahora insertaremos ficheros de distinto tipo

$cabecera .= "Content-Type: multipart/mixed;".$UN_SALTO; 

# insertamos el valor de boundary haciéndola igual a  $separador
# y acabamos con DOS SALTOS porque es el FINAL DE LA CABECERA

$cabecera .= " boundary=$separador".$DOS_SALTOS; 

/* Parte primera del envio -Mensaje en formato HTML
   ================================================

Separador inicial
------------------------------- */
$texto ="--$separador".$UN_SALTO;

/* Encabezado parcial
   ------------------  */
/* especificamos que este primer elemento
será texto y que irá codificado en formato 7 bits */

$texto .="Content-Type: text/html; charset=\"ISO-8859-1\"".$UN_SALTO; 
$texto .="Content-Transfer-Encoding: 7bit".$DOS_SALTOS; 

/* Contenido de esta parte del mensaje
   -----------------------------------*/
# ya teniamos escrito el texto del mensaje más arriba
# simplemente lo añadimos a la cadena de texto

  $texto .= $mensaje;

  #la variable $texto recoge esta parte del documento
  # la uniremos al final con las siguientes
 
/*  Separador de partes
    -------------------- */

$adj1 = $UN_SALTO."--$separador".$UN_SALTO; 

/* Parte segunda de mensaje -Fichero adjunto nº 1
   ==================================================== */

/* Encabezado parcial
   ------------------  */
# especificamos el tipo de contenido image/jpeg
# ya que ese será el documento que vamos a enviar
# ponemos el nombre del fichero (debemos tenerlo en el servidor
# con ese mismo nombre)
# establecemos in line como disposición para que pueda ser visualizado
# directamente en el cuerpo del mensajes
# en filename le asignamos el nombre con el que queremos que sea
# recibido por el destinatario
# por ultimo especificamos la codificacion como base64

$adj1 .="Content-Type: image/jpeg;";
$adj1 .=" name=\"casa08.jpg\"".$UN_SALTO;  
$adj1 .="Content-Disposition: inline; ";
$adj1 .="filename=\"leoncio.jpg\"".$UN_SALTO;
$adj1 .="Content-Transfer-Encoding: base64".$DOS_SALTOS; 

/* Lectura previa del fichero a adjuntar
   ------------------------------------------  */
    # abrimos el fichero en modo lectura (r)
   # y leemos todo su contenido midiendo previamente
   # su longitud con filesize
   # recogemos en $buff el contenido del fichero
   # y cerramos después

      $fp = fopen("casa08.jpg", "r"); 
           $buff = fread($fp, filesize("casa08.jpg")); 
       fclose($fp); 

/* Codificación del fichero a adjuntar
   ------------------------------------------  */
# codificamos en base 64 y troceamos en lineas de 76 caracteres
# y añadimos el resultado a la variable adj1

$adj1 .=chunk_split(base64_encode($buff)); 

/*  Separador de partes
    -------------------- */

$adj2 = $UN_SALTO."--$separador".$UN_SALTO; 

/* Tercera parte de mensaje -Fichero adjunto nº 2
   ==================================================== */

/* Encabezado parcial
   ------------------  */
# los contenidos del encabezado son similares al caso anterior
# con la salvedad de que el contenido es ahora
# application/octet-stream ya que contiene un fichero ejecutable
# y la disposicion es attachment, no tiene sentido tratar
# de visualizar un fichero zip

$adj2 .="Content-Type: application/octet-stream;";
              $adj2 .=" name=\"apachito.zip\"".$UN_SALTO; 
$adj2 .="Content-Disposition: attachment;
               filename=\"apachito.zip\"".$UN_SALTO;
$adj2 .="Content-Transfer-Encoding: base64".$DOS_SALTOS; 

/* Lectura previa del fichero a adjuntar
   ------------------------------------------  */
   # abrimos el fichero en modo lectura (r)
   # y leemos todo su contenido midiendo previamente
   # su longitud con filesize
   # recogemos en $buff el contenido del fichero
   # y cerramos después

      $fp = fopen("apachito.zip", "r"); 
         $buff = fread($fp, filesize("apachito.zip")); 
      fclose($fp); 

/* Codificación del fichero a adjuntar
   ------------------------------------------  */

$adj2 .=chunk_split(base64_encode($buff)); 

/*  Separador final YA NO HAY MAS PARTES
    ---------------------------------------- */

$adj2 .=$UN_SALTO."--$separador".$UN_SALTO; 

/*  Unión de todas las PARTES
    ---------------------------------------- */
# unimos en la variable mensaje todos los elementos
# y lo hacemos por el orden en el que fueron creados

  $mensaje=$texto.$adj1.$adj2;

/*  Envio del mensaje
    ---------------------------------------- */
  
if(mail($destinatario, $titulo, $mensaje,$cabecera)){
	echo "mensaje enviado";}else{print "ha habido problemas";
}

?>