Procesando mails con procmail y PHP

Este año quiero poner cosas más, um, edificantes en mi blog. Así que empezaré comentando esto que picó mi interés hace (muchas) semanas atrás.

Nestor Sertzen nos cuenta su forma de procesar mails usando procmail y PHP (y bash) aquí y aquí, sin embargo la forma cómo lo hace es un tanto ineficiente.

Su flujo básicamente es:

  • Recibir el correo con procmail
  • Pasarle el correo a un script en bash
  • El script en bash crea un fichero temporal con las últimas 5 líneas
  • El script en bash llama al script PHP con el nombre del fichero temporal
  • El script en PHP procesa la información y escribe a STDOUT, que está redireccionado a “/home/nestor/proceso”
  • El control regresa al script de bash, quien envía por mail el contenido de “/home/nestor/proceso”
  • Las ineficiencias principales son las siguientes:

    1) Usar bash para recortar las últimas 5 líneas del correo. Esto lo podemos hacer en el mismo script de PHP ya que de todas formas vamos a tener que recibir todo el mensaje.
    2) Usar un fichero temporal para pasarle las líneas a PHP. Bueno, esto no tiene mucho de malo, pero podemos evitar esto recibiendo de frente el mensaje con PHP.
    3) Esta falla si es grave: la redirección de la salida del script de PHP a “/home/nestor/proceso”. Si dos procesos PHP coinciden, uno puede chancar el fichero del otro. No hay una diferenciación por nombre como sí se hace previamente con el fichero temporal.
    4) El script de bash envía el resultado usando el comando “mail”. Esto también lo podemos hacer en el mismo PHP, con lo cual nos evitamos el posible conflicto descrito en el punto 3.

    Entonces, lo podemos mejorar de la siguiente forma:

  • Recibir el correo con procmail
  • Procesarlo todo con PHP
  • Profit!
  • El siguiente ejemplo está basado en un script mío llamado littlesister-getaddress.php. Lo que hace es recopilar el “From:” de todos los mails que me llegan.
    Mi script también es hackish, pero sirve de ejemplo. :)

    Llamamos al script de PHP directamente desde procmail:

    :0:
    * ^Subject.*(Numera)
    | /home/jgwong/bin/littlesister-getaddress.php
    

    Y en el script de PHP leemos todo el correo para procesarlo:

    #!/usr/bin/php
    <?php
    // Little Sister GetAddress 1.0
    // written by jaime g. wong <jaguar@paperclip.com.pe>
    
    $address_file = "/home/jgwong/.little-sister";
    
    $list = file ($address_file);
    
    $f = fopen ("php://stdin", "r");
    
    while ($line = fgets ($f)) {
        echo $line;
        
        if (preg_match ("/^From: (.+?)\$/", $line, $match)) {
            $email = trim ($match[1]);
            
            // ignore rules
            if (in_array ($email . "\n", $list) || strpos ($email, "orkut")) {
    //            echo "X-LittleSister: Found " . $email . "\n";
            }
            else {
                $e = fopen ($address_file, "a");
                fputs ($e, $email . "\n");
                fclose ($e);
            }
        }
    }
    
    ?>
    

    Lo importante del script es cómo se lee el contenido del mail desde procmail, que viene por STDIN y luego se procesa. No hay ficheros temporales intermedios, lo cual nos evita posibles conflictos. Escribimos en STDOUT el contenido recibido para que procmail siga con su flujo. Fíjense que hay un código comentado donde añadía una cabecera más al cuerpo del mail.

    Me quedé sin tiempo, mas espero que les sea útil. Si descargamos alguna librería para parsear mails (seguro hay alguna en PEAR) podemos hacer un poderoso script para procesar nuestros mails.

    Una idea que tengo para reducir mis distracciones en el trabajo es un filtro por importancia. Mi idea es retener mensajes no importantes por cierto tiempo e inyectarlos en mi buzón de entrada. Así los mensajes importantes (los del jefe, los de clientes VIP o cuentas especiales de notificación) sí pasan inmediatamente.