Nuevo proyecto en 5 horas: UsayTira.me, direcciones de correo de usar y tirar explicado paso a paso

Parece que últimamente me aburro mucho :P. Hace unos días, leyendo un artículo, se me ocurrió de nuevo explicar cómo se hacen esos sistemas de correo instantáneos que se suelen utilizar para registrarse en webs y que después no te envíen spam :P. La idea me pareció muy adecuada para poner un ejemplo práctico de algo que vimos hace tiempo sobre otras utilidades para un servidor de correo y, tal y como me ocurrió hace unos meses, lo que era un artículo se convierte en proyecto.

La idea, por tanto, es crear un sistema que, sin necesidad de ningún registro, te permita crear una cuenta de correo y recibir y leer emails en ella por espacio de una hora, al cabo de este tiempo la cuenta se autodestruye y todos los emails serán devueltos. En nuestra aplicación tendremos dos opciones para crear la cuenta, aleatoria o personalizada, creo que no hacen falta más explicaciones. Una vez usas una cuenta puedes volver a ella más tarde cuando la necesites volviendo a crear una cuenta personalizada con el mismo usuario. Esto es útil, por ejemplo, para que te recuerden la contraseña que utilizaste para registrar en aquella web de descarga de películas y de la que ya no te acuerdas ;).

Qué necesitamos

  • Servidor Linux con Qmail como MTA.
  • Apache, PHP y MySQL.
  • Pear MimeDecode: para procesar los correos entrantes con PHP.
  • Una plantilla superchula de FreeCssTemplates
  • Jquery: para todo lo que es ajax y Javascript
  • ZeroClipboard:  para copiar y pegar automáticamente
  • Jquery ScrollTo: pluggin para desplazar el scroll automáticamente.
  • Una imagen de “Cargando” para las acciones ajax que personalizas aquí.
  • Diccionarios de palabras “aleatorias”. Aquí hay unos cuantos.
  • Adodb (opcional) para el acceso a base de datos.

Eso es todo, sólo hay que juntar las piezas adecuadamente.

Preparando Qmail

Nuestro primer paso, antes de ponernos con los temas puramente web, será configurar adecuadamente el servidor de correo para nuestro propósito. Para ello necesitamos crear un usuario del sistema que reciba todo el correo dirigido a un dominio. Esto lo podemos hacer del siguiente modo:

adduser -g users -s /dev/null usaytirame
passwd usaytirame UNACLAVESUPERCOMPLICADA

Añadimos nuestro nombre de host en:

/var/qmail/control/rcpthosts

usaytira.me

Y el usuario al que dirigiremos los correos en:

/var/qmail/control/virtualdomains

usaytira.me:usaytirame

Reiniciando Qmail conseguiremos que los correos enviados a cualquier cuenta del dominio vayan al buzón del usuario indicado, es decir cualquiercosa[arroba]usaytira.me.

Pero no queremos que los correos vayan al buzón del usuario sino simplemente procesarlos. Para eso editamos el archivo:

/home/usaytirame/.qmail-default

|preline /usr/bin/php /home/usaytirame/procesa.php

Sólo con esa línea. Con este comando conseguimos redirigir los correos entrantes a un script en el que podremos recuperarlos y reutilizarlos a nuestro antojo como veremos a continuación.

Procesando los emails entrantes

Vamos a comenzar por crear una base de datos donde guardaremos los emails recibidos. Como queremos poder acceder a los emails dirigidos a cada cuenta independientemente, haremos dos tablas, una (emails) la utilizaremos como tabla maestra para las cuentas de correo que se creen y en la otra (correos) iremos almacenando los emails recibidos para cada una de esas cuentas.  La estructura sería poco más o menos la siguiente:

CREATE TABLE IF NOT EXISTS `emails` (
  `idEmail` int(11) NOT NULL auto_increment,
  `fecha` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
  `email` varchar(255) NOT NULL,
  `ip` varchar(15) NOT NULL,
  PRIMARY KEY  (`idEmail`),
  KEY `email` (`email`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

CREATE TABLE IF NOT EXISTS `correos` (
  `id` int(11) NOT NULL auto_increment,
  `idEmail` int(11) NOT NULL,
  `de` varchar(255) NOT NULL,
  `para` varchar(255) NOT NULL,
  `subject` varchar(255) NOT NULL,
  `fecha` varchar(255) NOT NULL,
  `body` text NOT NULL,
  `fullmail` text NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `idEmail` (`idEmail`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

Creo que es suficientemente descriptiva. El campo fecha de emails nos servirá para controlar los 60 minutos de duración máxima.

Pues ya tenemos todo preparado. Veamos cómo procesamos los emails.

/home/usaytirame/procesa.php

include ("mimeDecode.php");

$email=file("php://stdin");
$email=implode("", $email);

$params['include_bodies'] = true;
$params['decode_bodies'] = true;
$params['decode_headers'] = true;
$params['input'] = $email;
$structure = Mail_mimeDecode::decode($params);

$subject = quoted_printable_decode(trim($structure->headers['subject']));
$ddate = quoted_printable_decode(trim($structure->headers['date']));
$from = quoted_printable_decode(trim($structure->headers['from']));
$to = quoted_printable_decode(trim($structure->headers['to']));

if(ereg("<(.*)>", $to, $p))
    $to=$p[1];
$to=strtolower($to);

Tenemos la primera parte del procesado preparada. De aquí debemos destacar:

$email=file("php://stdin");

Con esto leemos desde la entrada estandar el contenido del email. Recordad que no estamos en una aplicación web sino en un script ejecutado en la consola del sistema.

La otra línea importante es:

$structure = Mail_mimeDecode::decode($params);

Con ella conseguimos procesar el email y separar su estructura en un array asociativo con los distintos parámetros. Os ayudará mucho ver el contenido de ese array:

print_r($structure)

Llegados a este punto podemos hacer una prueba. Necesitamos el contenido completo de un email, podemos sacarlo de nuestro cliente de correo o del propio servidor.

cat prueba.eml | /home/usaytirame/procesa.php

Si todo ha ido bien veremos en pantalla un array con la estructura del correo.

No voy a detallar todo el proceso ya que alargaría mucho el artículo. Vamos con el siguiente paso:

$query="select idEmail from emails where email=".$conn->quote($to);
$rs=$conn->Execute($query);
if($rs->recordcount()==0){
        exit(100);
}else{
        $idEmail=$rs->fields['idEmail'];
        $content = get_content($structure);
        $query="insert into correos
            (idEmail, de, para, subject, fecha, body, fullmail)
            VALUES
           ($idEmail,
            ".$conn->Quote($from).",
            ".$conn->Quote($to).",
            ".$conn->Quote($subject).",
            ".$conn->Quote($ddate).",
            ".$conn->Quote($content).",
            ".$conn->Quote($email).")";
        $rs=$conn->Execute($query);
}

En la primera parte del script comprobamos si la cuenta a la que va destinado el email existe en nuestra base de datos, si no, muy importante, devolvemos un código 100 que indica a qmail que debe devolver el correo ya que no existe el usuario.

Si la cuenta existe recogemos el cuerpo del mensaje. Yo lo hago con la función get_content, que analiza la estructura del correo y devuelve el contenido. Esta parte os la dejo a vosotros. Básicamente consiste en comprobar las distintas partes que puede tener un correo y devolver lo que estimemos oportuno. Un detalle muy importante a tener en cuenta es la codificación tanto del email como de nuestra base de datos y la aplicación web. En mi caso las dos últimas están en UTF-8, con lo que debo convertir todos los textos del email a esta misma codificación. La estructura que teníamos inicialmente en un array tendrá parámetros que nos indican el charset en el que viene el email. Las funciones de conversión de PHP te pueden ser útiles: iconv, utf8_encode, etc.Finalmente introducimos todos los campos del email en la base de datos.

Puedes volver a probar a procesar el email de prueba tal y como hicimos antes. Recuerda que debes añadir el registro de la tabla emails para que  guarde el correo, si no la cuenta no existirá. Una vez te funcione desde la línea de comandos ya puedes probar a enviarte un correo real :).

La aplicación web

No creo que hacer la parte web propiamente dicha necesite muchas explicaciones. Tenemos ya todos los elementos preparados, sólo debemos añadir los formularios para crear la cuenta de correo (aleatoria o personalizada) y, con un poco de ajax, ir cargando los correos a medida que van llegando. No  hay más truco.

Añadiré, eso sí, algunas aclaraciones interesantes.

Para crear las cuentas aleatorias, en vez de utilizar una secuencia aleatoria de números y letras, que daría como resultado algo ininteligible, usamos los diccionarios que comentaba más arriba. Los importamos en una tabla de la base de datos y simplemente tenemos que buscar aleatoriamente una palabra que no esté utilizada todavía como cuenta de correo, sencillo y muy impactante visualmente ya que estás ofreciendo cuentas legibles y con sentido.

Como en cualquier otra aplicación accesible públicamente, hay que añadir algún tipo de mecanismo de seguridad. En mi caso lo he hecho implementando una blacklist de direcciones IP. Cada vez que se crea una cuenta actualizo en una base de datos el número de cuentas que se han creado desde esa IP, si pasa del límite que estimemos oportuno, esa IP se pasa a la tabla de lista negra y cuando intente crear una nueva cuenta no se le dejará.

Nos falta una cosa: Eliminar las cuentas que tienen más de una hora. Muy sencillo, una tarea en el CRON que ejecuta un script que lanza una consulta a la base de datos que elimina las cuentas (y sus correos asociados) que se crearon hace más de 60 minutos.

Finalmente he añadido la opción de reiniciar esos 60 minutos de tiempo, simplemente actualizando el timestamp de la base de datos y algunos efectos visuales para plegar y desplegar los mensajes usando Jquery.

No hay mucho más, en unas cinco horas tenemos la aplicación hecha y funcionando.

Conclusiones

Como conclusión, la misma que hice hace unos meses con el primer proyecto. La copio tal cual porque es igual de válida.

Bueno, y todo este rollo ¿para qué?. Pues muy sencillo, para que veais que hoy en día la tecnología está al alcance de todos, es sencillo y rápido crear un proyecto en Internet, hay de todo por todas las esquinas, la tecnología no es lo importante, lo que verdaderamente cuenta es cómo mueves ese producto tecnológico para rentabilizarlo y obtener un beneficio de él.

Ya tengo mi proyecto superchulo funcionando, sólo me ha costado unas 5 horas de trabajo. Le he puesto un poco de Adsense por aquí y por allí. ¿Y ahora qué? ¿A esperar a que la gente entre y me haga millonario? 😛 Es mucho más complicado que eso como todos sabéis, primero tienes que tener una masa de usuarios elevada que le dé movimiento al proyecto y después tienes que conseguir que la mayoría de ellos sean gente normal, no gente técnica, usuarios avanzados que no pagamos por nada ni pinchamos en publicidad 😛 .

Hoy en día, en Internet, como en cualquier negocio, las técnicas de marketing y venta son mucho más importantes que la tecnología en sí misma, es duro reconocerlo, pero es así. De nada sirve que tengas el mejor producto del mundo mundial si no consigues que la gente lo utilice y se deje dinero, así de claro. Si tienes los conocimientos adecuados para mover el negocio, no te preocupes, la tecnología te la aporta cualquier partner por un módico precio, pero poner en manos de otro toda la estrategia de ventas de tu negocio no está tan claro ¿no?.

Espero que os sirva de algo el artículo. He querido mostrar, fundamentalmente, cómo utilizando algunas librerías que puedes obtener sin coste puedes hacer algo realmente útil y funcional con muy poco esfuerzo. Seguro que sacáis alguna idea.

Perdón por el rollo 😛 , al final me ha costado mucho más escribir el artículo que implementarlo.

Podíamos haber añadido una opción que he visto por ahí que consiste en crear una cuenta automáticamente cada vez que entra un email para una cuenta que no existe, pero estaríamos creando cuentas para todo el spam que recibamos, así que prefiero no hacerlo. Si quisierais hacerlo creo que ya sabéis cómo.

2 comentarios en “Nuevo proyecto en 5 horas: UsayTira.me, direcciones de correo de usar y tirar explicado paso a paso

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *