Enviar email con archivo adjunto con PHP

Enviar email con archivo adjunto con PHP

Hace un montón que no hago una entrada y la verdad que ya me toca.
Lo que vamos a hacer es crear un formulario para enviar un correo con archivos adjuntos con php y AttachMailer.php. Sabemos que para eso ya existe gmail pero ¿y si quisiéramos enviarlo desde nuestra página web sin utilizar un cms tipo wordpress?

Puedes descargarte el archivo al final de la entrada.

Demo

 

Vamos a empezar.

Para éste tutorial sería conveniente que tuvieras conocimientos básicos de PHP y HTML.

Primero de todo necesitamos crear un archivo index.php con un formulario como este:

<!DOCTYPE html>
<html lang="es">
<head>
 <meta charset="UTF-8">
 <title>envio de emails con archivos adjuntos</title>
</head>
<body>
 <div id="container">
 <h1>Envio de emails con archivos adjuntos - <a href="http://www.webcamp.es">Webcamp.es</a></h1>
 <form action="send.php" method="post" enctype="multipart/form-data">
 <fieldset>
 <legend>rellena el formulario</legend>
 <ul>
 <li>
 <label for="nombre">Nombre:</label>
 <br>
 <input type="text" id="nombre" name="nombre" placeholder="Nombre" required>
 </li>
 <li>
 <label for="mail">E-mail:</label>
 <br>
 <input type="email" id="mail" name="email" placeholder="E-mail del emisor" required>
 </li>
 <li>
 <label for="mailr">E-mail del receptor:</label>
 <br>
 <input type="email" id="mailr" name="emailr" placeholder="E-mail del receptor" required>
 </li>
 <li>
 <label for="adjunto">Archivo adjunto</label>
 <br>
 <input type="file" id="adjunto" name="adjunto" required>
 </li>
 <li>
 <label for="asunto">Asunto:</label>
 <br>
 <input type="text" id="asunto" name="asunto" placeholder="Asunto" required>
 </li>
 <li>
 <label for="msn">Mensaje:</label>
 <br>
 <textarea name="msn" id="msn" rows="10" required></textarea>
 </li>
 <li>
 <input type="submit" value="Enviar">
 </li>
 </ul>
 </fieldset>
 </form>
 </div>
</body>
</html>

Como vemos, en la etiqueta del <form> hemos añadido un método post, un action a send.php, que es el archivo que enviará el formulario y un enctype multipart/form-data. Éste último es necesario si queremos enviar archivos adjuntos.

Dentro del mismo, hemos añadido una lista con:

– Un input de tipo texto para el nombre.

-Dos inputs de tipo email. Uno para el emisor del correo y otro para el receptor del mensaje.

-Un input de tipo file para añadir el archivo que queremos adjuntar.

-Un input de tipo texto para el asunto del mensaje.

-Y un textarea para el mensaje.

Cada uno de ellos tiene un name que es el que utilizaremos para recoger los datos en el archivo send.php y un required que es un atributo de html5 que hace que no se envíe el correo si el campo está vacio.

El problema es que en algunos navegadores y sobretodo en dispositivos móviles el atributo required no funciona, así que tenemos que validarlo mediante jQuery.

Antes del cierre de la etiqueta </body> añadimos el script de jQuery mediante url:

<script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>

Y justo debajo añadimos lo siguiente:

<script>
$(document).ready(function(){
 $('form').submit(function(){
 if($('input[type="text"]').val() == '' || $('input[type="email"]').val() == '' || $('input[type="file"]').val() == '' || $('textarea').val() == ''){
 alert('Rellena todos los campos');
 return false;
 }
 });
 });
</script>

Lo que básicamente hace es que si al enviar el formulario «$(‘form’).submit» y los campos del formulario están vacíos «.val()» que salte la alerta con el mensaje «Rellena todos los campos» y devuelva falso para que no se envíe el formulario.

Para darle un poco de color al formulario añadiremos unos estilos css antes del cierre de la etiqueta </head> y entre las etiquetas <style> y </style> añadimos esto:


body {
background: #f5f5f5;
font-family: Arial, Verdana, sans-serif;
}
#container {
background: #fff;
border: 1px solid #cecece;
max-width: 1170px;
margin: 20px auto 0 auto;
padding: 20px;
text-align: center;
}
h1 {
color: #636363;
}
a {
color: #9fcd32;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
form {
max-width: 500px;
margin: 0 auto;
}
form fieldset {
background: #f5f5f5;
}
form legend {
color: red;
font-size: 20px;
font-weight: bold;
text-transform: uppercase;
}
form ul {
padding: 0px;
}
form ul li {
list-style-type: none;
text-align: left;
margin-top: 10px;
}
form ul li:last-child {
text-align: center;
}
form ul li input[type="text"],form ul li input[type="email"], form ul li textarea {
border: 1px solid #cecece;,
border-radius: 3px;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
-o-border-radius: 3px;
padding: 7px;
width: 96%;
}
form ul li input[type="submit"] {
background: red;
border: none;
color: #fff;
cursor: pointer;
font-size: 16px;
font-weight: bold;
padding: 10px;
text-transform: uppercase;
width: 50%;
}
.msn-ok, .msn-ko {
color: #fff;
padding: 10px;
text-align: center;
width: 65%;
margin: 20px auto;
}
.msn-ok {
background: #22AF22;
}
.msn-ko {
background: #CC2F2F;
}

Una vez creada la página del formulario, tenemos que crear el archivo que hará que esto funcione.
Creamos un artchivo llamado send.php y le añadimos lo siguiente:

<?php

class Email {

 //nombre
 var $nombre;
 //email del emisor
 var $mail;
 //email del receptor
 var $mailr;
 var $asunto;
 //mensaje
 var $msn;
 //archivo adjunto
 var $adjunto;
 //enviar el mensaje
 private $sender;
 //url para redireccionar
 private $url;

 //función constructora
 public function __construct(){
 //cada uno de ellos es el parámetro que enviamos desde el formulario
 $this->nombre = $n;
 $this->mail = $m;
 $this->mailr = $mr;
 $this->asunto = $a;
 $this->msn = $ms;
 $this->adjunto = $ad;
 }

 //método enviar con los parámetros del formulario
 public function enviar($n,$m,$mr,$a,$ms,$ad){
 //si existe post
 if(isset($_POST)){

 //si existe adjunto
 if($ad) {
 //añadimos texto al nombre original del archivo
 $dir_subida = 'fichero_';
 //nombre del fichero creado -> fichero_nombreArchivo.pdf
 $fichero_ok = $dir_subida . basename($ad);
 //y lo subimos a la misma carpeta
 move_uploaded_file($_FILES['adjunto']['tmp_name'], $fichero_ok);
 }
 //creamos el mensaje
 $contenido = '
 <h2>Nuevo mensaje de: '.$n.'</h2>
 <hr>
 Email: <b>'.$m.'</b><br>
 Mensaje: <br><b>'.$ms.'</b><br>
 ';
 //adjuntamos el archivo necesario para enviar los archivos adjuntos
 require_once 'AttachMailer.php';

 //enviamos el mensaje (emisor,receptor,asunto,mensaje)
 $this->sender = new AttachMailer($m, $mr, $a, $contenido);
 $this->sender->attachFile($fichero_ok);
 //eliminamos el fichero de la carpeta con unlink()
 //si queremos que se guarde en nuestra carpeta, lo comentamos o borramos
 unlink($fichero_ok);
 //enviamos el email con el archivo adjunto
 $this->sender->send();
 //url para redireccionar
 $this->url = 'http://www.webcamp.es/email';
 //redireccionamos a la misma url conforme se ha enviado correctamente con la variable si
 header('Location:'.$this->url.'?s=si');
 }
 else{
 //redireccionamos a la misma url conforme NO se ha enviado correctamente con la variable no
 header('Location:'.$this->url.'?s=no');
 }
 }
}

//llamamos a la clase
$obj = new Email();
//ejecutamos el método enviar con los parámetros que recibimos del formulario
$obj->enviar($_POST['nombre'], $_POST['email'], $_POST['emailr'], $_POST['asunto'], $_POST['msn'], $_FILES['adjunto']['name']);

?>

Aunque ya está bastante comentado el código, hagamos un repaso de todo.

Primero creamos la clase Email que contendrá toda la chicha.
Creamos los distintos atributos que recibimos del formulario (nombre, email, email del receptor, asunto, mensaje, archivo adjunto) y dos atributos privados para enviar el correo y la url donde redireccionaremos después de enviar el formulario.
Justo después creamos la función constructora que se encarga de crear las acciones a la hora de instanciar el objeto y pasarle por parámetro al método enviar los ditintos atributos.
Después creamos el método enviar y le pasamos los parámetros que recibimos del formulario.
Dentro creamos una condición de si existe un post «if(isset($_POST))» y dentro otra si existe un archivo adjunto «if($ad)».En el caso de que exista, creamos una variable que es el prefijo que añadiremos al nombre original del archivo. Ésto sirve más que nada si queremos guardarnos el archivo en nuestra carpeta y evitar que se añadan más de un archivo con el mismo nombre. Podemos poner lo que nos de la gana pero en nuestro caso y como veremos más adelante, no nos hará mucha falta porque eliminaremos el archivo justo después de enviar el mensaje.

Y subimos el archivo con move_uploaded_file.

Creamos la variable $contenido con el contenido del mensaje al que añadiremos el nombre, email y el mensaje donde podemos ver que se puede añadir código html.

Llamamos al archivo AttachMailer.php que es el que se encarga de enviar el correo con el archivo adjunto.

Creamos el objeto con AttachMailer adjuntándole (emisor,receptor,asunto,mensaje). Después viene lo que decíamos anteriormente de eliminar el archivo que acabamos de subir porque en nuestro caso no nos interesa tener la carpeta llena de archivos y lo hacemos con unlink y enviamos el mensaje con $this->sender->send().

Finalmente y si todo a ido a la perfección, redireccionamos con header y a la url le añadimos una variable «s» con el valor «si«. Y si no hay post redireccionamos con el mismo método pero con el valor «no» para la variable «s».

Creamos el objeto $obj y ejecutamos el método enviar con los distintos parámetros que recibimos del formulario como por ejempo $_POST[‘nombre’].

Si os fijáis, justo después de enviar el mensaje, a la url se le ha añadido ?s=si que es la variable que le pasamos por get una vez se ha realizado todo el proceso correctamente.

Ya solo nos queda añadir una condición al archivo index de si se ha enviado el mensaje o no.

En nuestro index.php, justo después del <h1>, le añadimos:

<?php
 //si se ha enviado el correo
 if(isset($_REQUEST['s'])){
 $ok = $_REQUEST['s'];
 if($ok == 'si'){
 echo "<div class='msn-ok'>¡Mensaje enviado correctamente!</div>";
 }
 elseif($ok == 'no'){
 echo "<div class='msn-ko'>Ha habido un error de envio...</div>";
 }
 }
 ?>

Es bien fácil: Si el valor de la variable «s» es si mostramos un mensaje y si es no pues otro. A este mensaje ya le hemos añadido estilo anteriormente en nuestro css.

Y ¡ya está! Espero que te haya gustado.

Descárgate el archivo y haz con el lo que te de la real gana 😉

 

Si tienes alguna duda puedes dejar un comentario o enviarme un mensaje privado en contacto.

19 Comentarios
  • Pepe
    Publicado el 12:16h, 22 marzo Responder

    Es genial, muchísimas gracias. 😀

  • Guadalupe Muñoz García
    Publicado el 10:50h, 26 septiembre Responder

    Hola! Perdona, donde se cambia el valor del email.. ¿?

    • santiakus
      Publicado el 10:37h, 02 octubre Responder

      Hola,

      esto lo puedes cambiar en el archivo send.php. Si tienes dudas me lo comentas y lo miramos con más detalle ok?

      Saludos 😉

  • FernandoQ
    Publicado el 17:29h, 06 noviembre Responder

    Hola estuve mirando tu formulario y esta muy cool… Pero queria que me ayudaras a editarlo para que enves de colocar «Email de Receptor» sea un receptor único o sea que el formulario se envie siempre al mismo receptor sin tener que ingresarlo manualmente

    Gracias

    • santiakus
      Publicado el 11:37h, 12 noviembre Responder

      Hola,

      ok, para hacer esto tienes que modificar tanto el archivo index.php como el send.php.

      — index.php —

      Borra la línea de la 24 hasta la 28 (es una lista), que es el campo del formulario que muestra esta opción.

      — send.php —

      En la línea 79 cambia el campo $_POST[‘emailr’] por el correo que quieras como receptor:

      $obj->enviar($_POST['nombre'], $_POST['email'], "tu_email@email.com", $_POST['asunto'], $_POST['msn'], $_FILES['adjunto']['name']);

      Pruébalo y cualquier cosa me comentas ok?

      Saludos 😉

      • Diego Rosale
        Publicado el 08:21h, 14 noviembre Responder

        Hola Buenos dias. No entiendo hice todo bien. lo estoy probando a travez de xampp, mi sitio en htdoc y al parecer todo va bien pero no me llega el mail a mi correo.

        Tambien te queria preguntar si en el caso quiero adjuntar hasta 3 imagenes como deberia hacer

        Desde ya muchas gracias por tu aporte y agradeceria una respuesta.

        • santiakus
          Publicado el 14:24h, 14 noviembre Responder

          Hola,

          si utilizas xampp no vas a recibir correo ninguno a no ser que lo subas a internet o utilices algún programa para este fín.. Yo para windows utilizo uno que se llama test mail server tool que lo que hace es simular el envío de correos desde un localhost, aunque muchas veces la estructura del mensaje (si utilizas html) no es la misma que se mostraría en gmail por ejemplo o a veces no muestra imágenes.. Pero funcionar funciona par verificar que el envío es correcto.

          A parte de esto, para poder añadir más de un archivo adjunto es más complicado pero lo puedes buscar por internet como send multiple files attach mailer php por ejemplo, que es la clase que utilizamos para adjuntar archivos…O si quieres puedo mirar de hacerlo yo pero como trabajo claro..

          Si quieres puedes enviarme un privado a info@webcamp.es y hablamos más detalladamente del tema ok? Aunque seguro que encuentras la solución tú mismo 😉

          ¡Saludos!

  • Lucia Castaño Marin
    Publicado el 20:19h, 21 febrero Responder

    Buenas tardes, tengo este mismo problema e intenté cambiar el $_POST[‘emailr’] exactamente por el email donde quiero que lleguen los correos pero no funciona. Me podrías indicar por favor si estoy haciendo algo mal?
    Muchas gracias

  • Stiven Hernandez
    Publicado el 04:39h, 16 abril Responder

    Hola amigo, me sirvió mucho su código pero tengo un problema.
    El archivo adjunto no se puede visualizar, y cuando lo descargo no se deja abrir

  • Jorge bastidas
    Publicado el 05:24h, 08 junio Responder

    que mas amigo gracia por tu información muy valiosa una consulta esto lo puedo usar para un formulario de registro de woocommerce

  • Wakoatl
    Publicado el 16:04h, 08 junio Responder

    una pregunta, si tengo activo el sevicio de Mercury mail desde el panel de control de Xampp ¿es posible hace pruebas desde mi localhost?

    Saludos!!

  • CARLOS ORTEGA
    Publicado el 04:41h, 23 junio Responder

    Muchisimas gracias está super genial tu ejemplo y me ayudo muchisimo!!!
    Podrías ayudarme, necesito que envié una copia oculta a otro correo como agrego la otra direccion de correo?
    Mil gracias de antemano.

  • Gamal El Sawaf
    Publicado el 09:18h, 25 julio Responder

    Hola, gracias por su aporte, se ve de maravilla, me gusta mucho, pero mi website, siempre me da 2 errores, y no se como hacer para modificarlos – Los errores son:
    Warning: move_uploaded_file(fichero_2018-02-08-CuevasLosTarantos-com.pdf): failed to open stream:

    Permission denied in D:\inetpub\webs\sawafcom\Test\send.php on line 51

    Warning: move_uploaded_file(): Unable to move ‘C:\PHPVersions\PHP55\uploadtemp\phpC4F9.tmp’ to ‘fichero_2018-02-08-CuevasLosTarantos-com.pdf’ in D:\inetpub\webs\sawafcom\Test\send.php on line 51

    Parse error: syntax error, unexpected ‘$docName’ (T_VARIABLE) in D:\inetpub\webs\sawafcom\Test\AttachMailer.php on line 34

    la otra cosa es como hago para adjuntar archivos determinados como ( x.jpg, x.doc, x.docx. x.pdf)

  • Therry Cruz
    Publicado el 03:27h, 04 septiembre Responder

    Excelente lo he probado y funciona salvo que presenta errores que registra en el archivo error_log asi:
    PHP Notice: Undefined variable: ad in send.php on line 27, en todas las variables.
    public function __construct(){
    //cada uno de ellos es el parámetro que enviamos desde el formulario
    $this->nombre = $n;
    $this->mail = $m;
    $this->mailr = $mr;
    $this->asunto = $a;
    $this->msn = $ms;
    $this->adjunto = $ad;

  • juan
    Publicado el 03:10h, 20 septiembre Responder

    subi el archivo a un servidor gratutito pero a al hora de correr el programa me marca error en el archivo send.php en la linea 24 a la 39 y en la linea 67

    • santiakus
      Publicado el 16:23h, 29 septiembre Responder

      Comprueba que tienes activada la opción «mail» de php en el servidor

  • Lucas
    Publicado el 20:43h, 30 septiembre Responder

    Hola, estoy probando agregar variables o reemplazar pero aparecen siempre las originales, cómo debo hacer para agregar un campo number ,y otro date para poder enviar junto con los otros datos?

    • santiakus
      Publicado el 08:20h, 09 octubre Responder

      Hola,

      si has añadido los nuevos campos en el archivo «index.php» tienes que recibirlos como POST en el archivo «send.php»

  • cristian
    Publicado el 19:38h, 23 noviembre Responder

    hola comunida una consulta como hago para ponerlo que suban varios archivos en adjuto ?

Añadir Comentario