miércoles, 19 de octubre de 2011

PHP - Enviar un mail con archivos adjuntos

LLevo un día peleándo con este tema!
No quería utilizar librerías y no tengo demasiado experiencia en este tema. Así que, después de investigar por la red, he conseguido confeccionar un código que funciona bastante bien. Y lo más importante, es que he entendido que hace cada línea de código.
A veces, con las prisas nos dedicamos a copiar y pegar, pero al final siempre es un atraso pq. funciona pero no sabemos lo que hemos hecho ... es mucho mejor perder un poco de tiempo (si se dispone de él claro) y comprender.

HTML:

<form accept-charset="utf-8" action="GME__trabaja_con_nosotros.php" class="trabaja" enctype="multipart/form-data" id="formulario" method="post">

<input type="text" id="nombre" name="nombre" value="Nombre" />
<input type="text" id="apellido" name="apellido" value="Apellidos" />
<input type="text" id="email" name="email" value="e-mail" />
<input type="text" id="telefono" name="telefono" value="Telefono" />
<input type="file id="filead" name="filead" />
<input type="checkbox" id="condiciones" name="condiciones" />
<input type="submit" value="Enviar Formulario />

</form>

En la parte del HTML lo más importante es el "enctype" del form:
Para que podamos adjuntar archivos tiene que ser:
enctype="multipart/form-data"

Encontramos una excelente explicación en:
http://w3schools.com/tags/att_form_enctype.asp



PHP:

<?php

if ($_POST){

$num = md5(time());

//MAIL BODY
$body = “
<html>
<head>
<title>Formulario Trabaja con nosotros</title>
</head>
<body style='background:#EEE; padding:30px;'>
<h2 style='color:#767676;'>Trabaja con nosotros</h2>";

$body .= "
<strong style='color:#0090C6;'>Nombre: </strong>
<span style='color:#767676;'>" . $_POST["nombre"] . "</span>";

$body .= "
<strong style='color:#0090C6;'>Apellidos: </strong>
<span style='color:#767676;'>" . $_POST["apellido"] . "</span>";

$body .= "
<strong style='color:#0090C6;'>Email: </strong>
<span style='color:#767676;'>" . $_POST["email"] . "</span>";

$body .= "
<strong style='color:#0090C6;'>Teléfono: </strong>
<span style='color:#767676;'>" . $_POST["telefono"] . "</span>";

$body .= "</body></html>";

$_name=$_FILES["filead"]["name"];
$_type=$_FILES["filead"]["type"];
$_size=$_FILES["filead"]["size"];
$_temp=$_FILES["filead"]["tmp_name"];

if( strcmp($_name, "") ) //FILES EXISTS
{
$fp = fopen($_temp, "rb");
$file = fread($fp, $_size);
$file = chunk_split(base64_encode($file));

// MULTI-HEADERS Content-Type: multipart/mixed and Boundary is mandatory.
$headers = "From: GME <gme@garciamunte.com>\r\n";
$headers .= "MIME-Version: 1.0\r\n";
$headers .= "Content-Type: multipart/mixed; ";
$headers .= "boundary=".$num."\r\n";
$headers .= "--".$num."\n";

// HTML HEADERS
$headers .= "Content-Type: text/html; charset=UTF-8\r\n";
$headers .= "Content-Transfer-Encoding: 8bit\r\n";
$headers .= "".$body."\n";
$headers .= "--".$num."\n";

// FILES HEADERS
$headers .= "Content-Type:application/octet-stream ";
$headers .= "name=\"".$_name."\"r\n";
$headers .= "Content-Transfer-Encoding: base64\r\n";
$headers .= "Content-Disposition: attachment; ";
$headers .= "filename=\"".$_name."\"\r\n\n";
$headers .= "".$file."\r\n";
$headers .= "--".$num."--";

}else { //FILES NO EXISTS

// HTML HEADERS
$headers = "From: GME \r\n";
$headers .= "MIME-Version: 1.0\r\n";
$headers .= "Content-Type: text/html; charset=UTF-8\r\n";
$headers .= "Content-Transfer-Encoding: 8bit\r\n";
}

// SEND MAIL
mail("laroca73@gmail.com", "WEB - Trabaja con nosotros" , $body, $headers);

echo "<div class='ok'>
<strong>El formulario se ha enviado correctamente.</strong></div>";

}
?>

Aunque visto así, tan ordenadito parece muy fácil ... me costó mucho encontrar un ejemplo que funcionara y que explicara un poco qué estaba haciendo.

El principal problema que encontré es que era capaz de enviar un mail con texto, y un mail con archivo adjunto pero no encontraba la manera de enviar texto+archivo adjunto en el mismo mail.

La clave está en las cabeceras.
El Content Type tiene que ser: multipart/mixed.
Y tenemos que definir un "boundary", es un separador único que nos permite utilizar diferentes cabeceras dentro del mismo mail.
Podemos encontrar una buena explicación en: http://www.w3.org/Protocols/rfc1341/7_2_Multipart.html

Este código es la base o el patrón, a partir de él podemos customizar el envío de mails controlando el peso de los archivos que permitimos subir (Ej/5Mb) o bien el tipo de archivos (Ej/.zip, .pdf ..etc)



Podemos ampliar esta en información en:
http://www.w3schools.com/php/php_file.asp
http://www.w3schools.com/php/php_file_upload.asp

Espero que os sirva de ayuda!




32 comentarios:

JD dijo...

Muy buen articulo, muy útil, tengo una duda. EL Multi-Header, el Html Header y el File header. ¿Son para poder enviar los archivos adjuntos y texto a la ves?

Laroca dijo...

Exacto.

Gracias,
Laroca.

notope dijo...
Este comentario ha sido eliminado por el autor.
Laura Rodríguez Castillo dijo...

Buenas,
el código está implementado y funciona. Igual al copiarlo me equivocado! Lo repasaré. Gracias por tus comentarios, ayudan a mejorar.

LordGraphic3 dijo...

Por fin. Eres el Héroe del dia... Llevaba una semana sin que me funcione mi formulario de envio con adjuntos. Hasta que copie tu código y lo lo modifiqué las variables y más... y Funcionó limpio y suave. Gracias. Muchas Gracias por el aporte.

Laura Rodríguez Castillo dijo...

En todo caso la heroína! Gracias por dejar comentario! Es super gratificante saber que los posts están ayudando a la gente!

zuri sadai dijo...

hola, tengo un problema,, al momento de usar tu codigo me dice que se ha enviado el mail correctamente, pero no me llega nada, sabes que podria ser?

gracias

Ignacio dijo...

hola tengo una duda osea mas que una duda un problema, al seleccionar un archivo para enviarlo se queda cargando la pagina y al final me muestra la pagina en blanco y no envia el correo, (al parecer es un problema con el fopen), por que al no adjuntar ningun archivo el correo se envia sin nungun problema, si alguien lo soluciono que me ayude pliss...(lo estoy probando en un hostin gratuito, 00webhost)

Laura Rodríguez Castillo dijo...

Buenas,
lo único que os puedo decir es que el código está implementando y funcionando. Aseguraros de que lo estais ejecutando en un servidor web que tenga instalado el servicio para enviar mails (yo esto no lo controlo).
Saludos!

Wysarri carlos rodríguez dijo...

Me ha costado mucho, pues he tenido que combinar el jaleo de código que ya tenía con el de esta entrada, pero funciona correctamente.

Lástima no saber mejor que hace
exactamente cada línea para entender mejor el código y poder aprovechar mejor sus posibilidades.

A los que tienen problema con que en el correo aparece el fichero y no el texto, revisad bien las etiquetas html del mensaje del correo, eso me la ha jugado.

Gracias y saludos.

Pedro Daniel dijo...

Gracias Laura por este artículo.

Lo he probado y funciona perfectamente.

Lo que llevo un par de dias intentado realizar una pequeña validación en PHP (en Javascript ha sido fácil ya que es independiente), al menos que obligue a la entrada de algunos datos antes de enviarlo y no lo consigo.

No sé si podrias echarme una mano, independientemente de que lo hagas o no, muchas gracias.

Pedro D.

CarlsWys dijo...

En respuesta a Pedro Daniel, eso se puede hacer de forma muy fácil con en atributo required (html5), mira en este enlace Validar formularios con HTML5 y CSS3.

Espero te sirva...

Claudio Delsahüt M. dijo...

Hola, dónde se reemplaza el mail donde llegará el adjunto?????


gracias <3

poKer223 dijo...

Hola.
Disculpa podrias decirme que tendria que agregar si quiero enviar 2 archivos adjuntos?.

yo cale copiando el if y los header de archivo y poniendo el array $files con el nuevo archivo tambien.

Bien Hecho dijo...

Hola tengo la misma pregunta de poker223, si alguien puede ayudar mil gracias es urgente.

Bien Hecho dijo...

que debo agregar para que se envíen varios archivos adjuntos?

Laura Rodríguez Castillo dijo...

Buenas,
hace tiempo que implementé el código y no me acuerdo bien, pero funciona.
"La clave está en las cabeceras.
El Content Type tiene que ser: multipart/mixed.
Y tenemos que definir un "boundary", es un separador único que nos permite utilizar diferentes cabeceras dentro del mismo mail."
Te recomiendo que lo copies y hagas un test sencillo.

Saludos,
Laura.

MCO dijo...

fantástico!! funciona estupendamente, era lo que buscaba, además muy mascadito y bien explicado. ¡felicidades máquina!!

gParla dijo...

Lo que pasa es que nos la das tan bien estructurado , que cualquiera se pone arevisarlo. I encima funciona.
De verdad, GRACIAS i FELICIDADES

Laura Rodríguez Castillo dijo...

Gracias!

Andres Osorio dijo...

Hola, primero gracias por el aporte, estuve varios días buscado, ahora, modifique el código y me funciona perfectamente al enviar el archivo adjunto, el problema es que cuando voy a enviar el formulario sin el archivo solo texto no me llega a el correo. si alguien tiene alguna solución gracias.

Francisco Palomares dijo...

Hola que tal una pregunta, si quiero adjuntar un zip, o un pdf como le tengo que hacer? ya que lo he intentado y el pdf lo manda vacío y el zip como ciclado ya que cada que lo descomprimo sale otro zip y así sucesivamente.

Saludos cordiales.

antonio cherneca dijo...

Hola. Que debo modificar para poder enviar solo un archivo sin nada mas desde mi web? Muchas gracias!!

andymora dijo...

Hola Laura, por equivocación te he enviado un email jeje, olvide cambiar ese dato en el form.

Frida FloreS dijo...

Hola, he probado con el codigo de los headers, yo solo necesito mandar un excel y un mensaje:
"Buen dia, aqui envio el reporte"

Pero haga lo que haga solo manda el adjunto.

Ayuda porfavor, alguna idea de que pueda ser el error?

Dany TT dijo...

Fantastico! me salvaste la vida con esto, ahora estoy buscando como limitar el tamano y tipo de archivos.
Alguna idea? lo que use parece no servir.

Gracias !

Noira dijo...

Hola!! He usado este código desde hace años funcionando, pero ahora tengo un nuevo hosting y no me funciona. No se si es por el hosting o es que hay cambios en la web últimamente. Lo has hecho funcionar recientemente en la web? Gracias.

Julio Custodio Carrasco dijo...

buenas gracias por el aporte, ami me sale este mensaje soy nuevo en esto y no se realmente como solucionarlo, al parecer tengo que configurar algo, las pruebas lo hago en mi laptop no he subido la aplicación a ningun servidor aun, alguien seria tan amable de explicarme como y que hacer para que me funcione ya que me sale esperando a localhost y despues me arroja este mensaje: Warning: mail() [function.mail]: Failed to connect to mailserver at "mail.YourDomain.com" port 25, verify your "SMTP" and "smtp_port" setting in php.ini or use ini_set() in C:\wamp\www\formularioconbd\clientes\enviar.php on line 87

LuisBendezu dijo...

quisiera que me ayudes.. eh copiado el codigo todo .. pero lo malo q cuando no cargo ningun archivo .. me envia con todo los datos q pongo en el formulario pero cuando cargo un archivo.. me llega solo el archivo y menos los datos del formulario ..nose cual puede ser el error

Cesar Amezcua dijo...

no me funciona

Cesar Amezcua dijo...


Cesar Amezcua dijo...

https://jsfiddle.net/Lo1cbkLz/