CONEXIÓN Y CONFIGURACIÓN DE INTERNET DESDE LINUX

Artículo 8: Procesado de correo con PROCMAIL

Autor: (c) Santiago Romero
Revista: NetOnline (Prensa Técnica) nº 19, Marzo-1999


Muchas veces nos gustaría distribuir el correo que nos llega en diferentes ficheros o cuentas de forma que pueda leerse separadamente los emails personales de los cientos de mensajes de las listas de correo, mientras que en otras ocasiones nos gustaría que hubiese una manera de auto responder ciertos emails o de eliminar correo de propaganda o spam. Esto es posible en Linux gracias a procmail.


Procmail es un procesador de correo autónomo que se ejecutará en nuestra máquina al producirse la llegada de un nuevo mensaje. En ese momento procmail será llamado automáticamente gracias al fichero .forward (como veremos en este artículo) o a través de sendmail, de tal modo que leerá el correo de la entrada estándar y abrirá el fichero .procmailrc que le indicará qué debe hacer con ese correo en función de una serie de reglas que nosotros le proporcionaremos y que comentaremos en la entrega de este mes. En un funcionamiento normal sin procmail, existe un fichero en /var/spool/mail (o en la cuenta de cada user, según configuraciones) con el nombre de cada usuario en el cual se amontonan uno tras otro los diferentes emails que se van recibiendo, concatenándose todos en el mismo fichero hasta que el usuario recoge el correo y el fichero es vaciado (aunque durante un tiempo todos los mensajes residen juntos en el mismo fichero). Mediante procmail podemos alterar ese proceso y eliminar mensajes, o dejarlos en otro fichero diferente atendiendo a un conjunto de reglas.

Las reglas de procmail se refieren al contenido del mensaje en sí (tanto la cabecera como el cuerpo del mismo), y nos permitirán eliminar correo propaganda o spam (si no todo, al menos sí gran parte de él), repartir los mensajes entre los diferentes usuarios de correo, pudiendo tener una sóla dirección email para todos los usuarios, pero utilizando algún campo especial para identificar a cada uno. También podremos separar el correo de las listas de correo, o por categorías, preparar autorespuestas (por ejemplo un autoenviador de nuestra clave PGP cuando nos sea pedida, o un aviso de que nos hemos ausentado y no podemos leer el correo) y, como veremos, muchas cosas más sólo limitadas a nuestra imaginación.


INSTALACION DE PROCMAIL

Procmail suele estar disponible en cualquier distribución Linux ya que es un componente muy activo de la misma al ser utilizado muchas veces por sendmail en la distribución del correo local de la máquina o red. Si no disponemos del mismo es posible obtenerlo de Internet en los ftps de las diferentes distribuciones (ftp.redhat.com, ftp.suse.org, etc.), e instalarlo vía rpm, dselect/dpkg o tar. La versión estable utilizada por el autor es la 3.10-12, aunque la versión variará normalmente en función de la distribución de la que se haya instalado. Si no se dispone del binario y tan sólo se tiene el código fuente, su compilación es muy sencilla, teniendo especial cuidado en el fichero Makefile (que especifica los parámetros de la compilación) y la variable BASENAME, que indica el directorio donde será instalado el paquete procmail. Tras esta observación se debe realizar un make install que compilará e instalará el paquete.


FUNCIONAMIENTO

Existen 2 maneras de instalar procmail. La primera de ellas es que sea utilizado por sendmail a la hora del reparto del correo, y la otra forma se realiza mediante un fichero de configuración de nombre .forward que contendrá la llamada a procmail de forma que éste se ejecute a la llegada de nuevos mensajes al Inbox de dicho usuario. Para saber si tenemos procmail integrado en sendmail se debe buscar la cadena apropiada en /etc/sendmail.cf:


[sromero] [~]$  cat  /etc/sendmail.cf  |  grep "^Mlocal"
Mlocal,     P=/usr/bin/procmail, F=(...etc...)

Si en dicha línea nos aparece la llamada a procmail, éste ya estará integrado en sendmail y podemos pasar directamente a su configuración propiamente dicha.

El fichero .forward sólo será necesario si procmail no es llamado por nuestro MTA (agente de correo), en cuyo caso se necesitará este fichero para llamar a procmail ante cada entrada de mensajes. Dicho fichero se creará en el home del usuario que desea utilizar procmail y contendrá una línea que llame a procmail y que defina el usuario al que debe ir a parar el correo:


|IFS=' '&&exec /usr/bin/procmail -f  || exit 75 #sromero

Este fichero debe tener permiso de lectura:

[sromero@compiler ~]$  chmod ugoa+r .forward

Cuando es llamado (de cualquiera de las 2 formas), procmail lee el mensaje de correo desde la entrada estándar. A continuación abre y lee el fichero .procmailrc de nuestro directorio home (si existe), examina las reglas contenidas en dicho fichero y decide el destino del mensaje (que puede ser devuelto, enviado a un usuario en concreto, autorespondido, borrado, etc.). Si el fichero .procmailrc no existe el mensaje es depositado en el Inbox habitual del usuario.

El conjunto de reglas de .procmailrc suelen ser de comprobación y búsqueda de cadenas de texto en el FROM (dirección de origen), SUBJECT (tema del mensaje), BODY (cuerpo del mensaje), etc. Como sencillo ejemplo, es posible especificarle a sendmail que si en el cuerpo del mensaje se encuentran las palabras "gane" y "dinero", o similares, elimine el correo (probablemente se trate de un correo spam o correo basura), o que si en el subject encuentra las palabras "clave" y "PGP", debe enviar al remitente de ese mensaje un texto con nuestra clave PGP.

Más concretamente, el fichero .procmailrc contiene un conjunto de reglas formados por instrucciones condicionales, variables y otras instrucciones. Cuando el mensaje es recibido, éste pasa a ser procesado (procmail = procesador de mail), es decir: se leen todas las reglas del fichero y se comprueba si el mensaje cumple alguna de ellas, en cuyo caso se ejecutará el subcódigo pertinente a dicha regla. En caso de no cumplirse ninguna el mensaje es añadido al final del fichero de mensajes por defecto (especificado como veremos por la variable $DEFAULT).


CONFIGURACION Y EJEMPLO

Lo primero que vamos a hacer es observar un ejemplo de .procmailrc antes de comentar las diferentes reglas que pueden usarse, para así ir viendo de qué manera le vamos a indicar a procmail las acciones a realizar con cada tipo de mensaje:


# ejemplo de .procmailrc
MAILDIR=$/var/spool/mail
DEFAULT=$MAILDIR/juan
LOGFILE=$MAILDIR/log

:0:
* ^From.*romario
/home/juan/Mail/mensajes_romario

:0:
* ^From.*Josema
!jefe@de.josema

:0
* ^Subject:.*prueba
 /dev/null

En en el ejemplo anterior, las 3 primeras líneas especifican los directorios de correo (MAILDIR), el fichero de entrada de emails por defecto (DEFAULT), y un fichero donde procmail indicará paso por paso todo lo que ha hecho en cada sesión (LOGFILE). A continuación se definen 3 reglas (comenzando todas ellas por :0), que son las siguientes:


:0:
* ^From.*romario
mensajes_romario

Todos los mensajes que contengan en la cabecera From (el remitente) la cadena "romario" serán dejados en el fichero "mensajes_romario". De esta manera, cuando llegue un email cuyo campo From sea From: romario@futbol.com, o From:admiradores@romario.com, éste será dejado en el fichero mensajes_romario. Si esta regla no se cumple (es decir, no aparece la cadena "romario" en el campo From), se pasa a comprobar si se cumple la siguiente regla, que en nuestro caso especifica que todos los mensajes provenientes de josema sean enviados a jefe@de.josema, acción realizada mediante el comando ! (cierre de admiración). La última regla especifica que todos los mensajes que contengan la cadena prueba en el asunto (Subject) deben ir a para a /dev/null (also así como la papelera de Linux). En caso de no cumplirse ninguna de las 3 reglas el mensaje irá a parar al fichero apuntado por $DEFAULT, usualmente /var/spool/mail/<nombre_usuario>, de forma que luego puedan ser recogidos por cualquier cliente de correo, como Kmail o Netscape.

Pero veamos más concretamente la sintaxis de procmail. Lo primero que veremos serán las diferentes variables de entorno que podemos modificar:

La asignación de estas variables puede realizarse en cualquier parte del fichero .procmailrc (no tiene porqué ser al principio del mismo), de la misma forma que pueden eliminarse si procmail se encuentra una línea con el nombre de una variable y sin asignarle ningún valor (ej: DEFAULT (intro)).

En principio, a partir de cada carácter '#' el texto hasta fin de línea es considerado como comentario (ignorado por procmail), con la excepción de las líneas en las que se definen condiciones, donde no es posible situar comentarios (sólo antes o tras ellas, pero nunca en la misma línea).


LAS REGLAS DE PROCMAIL

Todas las líneas que comiencen por :0 o :0: indican el comienzo de una nueva regla. La diferencia entre :0 y :0: (los 2 puntos finales de la segunda) consiste en que en este segundo caso al escribir en el fichero se bloquea para que no pueda hacerlo otro proceso al mismo tiempo que nosotros y no se corrompa el mismo.

Dentro de cada regla, las líneas que comienzan por un carácter '*' indican la condición de la regla, mientras que todo lo que siga a las condiciones (pues puede haber más de una condición) se considerarán comandos a ejecutar (excepto las líneas de comentario), tales como en el ejemplo anterior el nombre de fichero (que indicaría a procmail que debe guardar el mensaje ahi), una dirección de correo precedida por ! (que le indica reenvío), o una referencia a /dev/null (borrado), así como la ejecución de cualquier otro comando Linux que deseemos. Pueden distiguirse 2 tipos de reglas: las que al cumplirse se finaliza el procesado del mensaje (terminales) y las que tras su ejecución se siguen realizando comprobaciones con otras reglas (no terminales).

Una regla tiene un aspecto similar al siguiente esquema:

:0 [opciones] [ : ]
* condicion A
* condicion B
* condicion C
       etc...
* condición N
comando a ejecutar

Tras cada :0 podemos utilizar las siguientes opciones:

Como se ha comentado, si no se indica ninguna opción las condiciones de la regla se aplican a la cabecera del mensaje (H), y pasando como entrada al comando tanto la cabecera (h) como el cuerpo del mensaje (b).


CONDICIONES

Las condiciones son propiamente la regla en sí, y en caso de que se cumplan se procederá a ejecutar el comando especificado pasándole el mensaje en función de las opciones que hubiesemos seleccionado (por defecto pasandole la cabecera y el cuerpo). Toda condición empieza por un símbolo '*' y suelen estar constituidas por expresiones regulares (del tipo de grep, rgrep, etc.) que consisten en búsquedas de cadenas de carácteres en las diferentes partes del mensaje. En una expresión regular se utilizan los siguientes símbolos:

Símbolo '^' -> Indica el comienzo de una línea.
Símbolo '$' -> Indica el final de una línea.
Símbolo '*' -> Indica cero o más veces.
Símbolo '?' -> Indica cero o una vez.
Símbolo '+' -> Indica una o más veces.
Símbolo '+' -> Cualquier carácter excepto un \n (salto de línea).
Símbolo [a-z] -> Que quede en un rango de carácteres (primero-último).
Símbolo [^a-z] -> Que no quede en un rango de carácteres (primero-último).
Símbolo '|' -> Permite especificar operación O ( a | b = 'a' o 'b' )

Al comienzo de la línea de condición tambien pueden existir opciones sobre esa condición:

Símbolo '<' -> Permite comprobar si el fichero tiene un tamaño menor al especificado.
Símbolo '>' -> Permite comprobar si el fichero tiene un tamaño mayor al especificado.
Símbolo '!' -> Invierte la condición (se cumplirá cuando la condición sea falsa).
Símbolo '$' -> Realiza susticiones de variables en las expresiones regulares.
Símbolo '?' -> Necesita el resultado que devuelve el programa especificado.

COMANDOS

Tras cada condición se especifica un comando para que sea ejecutado si la regla se cumple. Distinguimos principalmente cuatro comandos básicos:

1. Fichero: Hace que procmail añada el mensaje al final del fichero, con otros posibles mensajes.
2. Directorio: Hace que procmail guarde el mensaje en el directorio con un nombre propio no repetido.
3.!direccion@email.es: Mediante el carácter '!' podemos enviar el mensaje a la dirección de correo especificada.
4.|programa: El carácter '|' permite ejecutar un programa/comando de linux. La salida del programa saldrá por la salida estándar, aunque se puede redirigir a cualquier lado con el redireccionamiento estandar de linux (>/dev/null, >fichero, etc). También es posible asignar la salida del programa a una variable de entorno.


LISTAS DE CORREO

Como ejemplo práctico vamos a utilizar procmail para separar los mensajes provenientes de una lista de correo de los mensajes normales, de modo que no los tengamos todos en el mismo buzón y se gane en claridad de lectura. Para ello simplemente hemos de buscar en el campo FROM del mensaje la dirección de la lista de correo.

Tomemos para ello la lista l-linux, de dirección l-linux@calvo.teleco.ulpgc.es. Cualquier mensaje que provenga de esa dirección será un mensaje de la lista, de modo que esos mensajes deberán ir a un fichero aparte del Inbox estándar. A continuación se muestra un .procmailrc que se podría utilizar para dicha separación:


# procmailrc para separar los mensajes
# de la lista l-linux
:0:
* ^From.*l-linux@calvo.teleco.ulpgc.es
l-linux.msgs

#si no es un l-linux, entrega normal.
La regla utilizada es muy sencilla:

* ^From.*l-linux@calvo.teleco.ulpgc.es
l-linux.msgs

Recordemos que * indica el comienzo de la regla, y que a continuación de * viene la condición de la misma. Esta contiene la cadena From.*l-linux@calvo.teleco.ulpgc.es con el símbolo^ delante. Esto quiere decir que cualquier línea que comience (^) por From, con cualquier número de carácteres (.*) y que contenga la cadena From.*l-linux@calvo.teleco.ulpgc.es cumplirá la regla y que por tanto ese mensaje debe ser grabado en el fichero l-linux.msgs (en el directorio apuntado por la variable $MAILDIR). En caso contrario, se entrega normalmente. El uso de .* es que tras el campo from pueden venir 0 o más carácteres (ver definiciones de condiciones), con lo que cadenas como "From", "From:", "FROM:" y "From, " antes de la direccion de correo serán reconocidas como cumplidoras de la regla.


EJEMPLOS MÁS AVANZADOS

Existen numerosos tutoriales y ejemplos sobre reglas de procmail en Internet. Uno muy interesante es aquel que nos permite eliminar todos los mensajes de un remitente determinado, con el fin de no leer ni sus mensajes directos ni mensajes respuesta a los suyos en una lista de correo. El siguiente filtra todos los mensajes recibidos de un usuario determinado:


:0
* ^Sender:  linux@calvo.teleco.ulpgc.es
{
    :0
    * ^From: juanjo@direccion.es
    /dev/null
    :0 B
    * (juanjo wrote)|(juanjo escribi)
    /dev/null
    :0
    l-linux.msgs
}

Como puede observarse en este ejemplo, mucho más elaborado, y basado en otro de una de las muchas páginas web dedicadas a procmail,en este caso hemos creado una regla compuesta de 3 condiciones mediante los operadores { y }. Cuando se detecta si el mensaje es de una lista de correo, se puede hacer distinción entre los mensajes enviados por juanjo@direccion.es (regla 1, comprobándolo en la cabecera, y son enviados a /dev/null, es decir, son eliminados), entre mensajes escritos por dicho usuario (comprobando la condición en el cuerpo del mensaje con la opción B), o (el resto de casos) dejando en el fichero deseado.

Otro ejemplo de este tipo (y muy sencillo) es la autorespuesta de nuestro sistema de correo a determinados emails, como envio de la clave PGP (cuando el Subject del mensaje contiene la cadena PGP es usual que nos la estén pidiendo), o autorespuestas para cuando nos vamos de vacaciones:


:0:
* ^Subject.*PGP
| (formail -r ; cat /home/juan/clavepgp.txt) | sendmail -t

En este caso clavepgp.txt es un texto con nuestra clave PGP lista para enviar, que pasamos a formail para que componga un mensaje que enviamos con sendmail. De la misma forma podemos autoresponder en vacaciones a todos los mensajes que sean recibidos, simplemente eliminando la condición. El único problema que puede presentarse es que un email nos sea devuelto, con lo que lo contestaríamos de nuevo (a nuestra dirección), nos llegaría, lo volveríamos a contestar, etc. Para evitar esto se utiliza una campo del mensaje llamado X-Loop que detectaremos antes de contestar, pues si está presente quiere decir que ese mensaje lo enviamos nosotros (lo activaremos en cada autorespuesta), y si no, que es un mensaje del exterior. El añadir un campo a la cabecerade un mensaje se realiza con formail (ver man formail), y lo debemos hacer en cada autocontestación:


formail -r -A"X-Loop: nosotros@direccion.es" 

A la hora de auto responder también deberemos detectar si ya existe dicho campo y no contestar en ese caso:


:0
* !^X-Loop: nosotros@direccion.es
| (formail -r -A"X-Loop: nosotros@direccion.es" ; 
 cat /home/juan/estoy_de_vacaciones.txt) | sendmail -t


Santiago Romero
Volver a la tabla de contenidos.