ÍNDICE

    1. Introducción.
        1.1 Qué es el Procmail?
        1.2 Formato de un mensaje
    2. Instalación del Procmail
    3. Cómo se usa
        3.1 Fichero .procmailrc básico
            3.1.1 Asignaciones
            3.1.2 Recipientes
        3.2 Expresiones regulares
        3.3 Otros ejemplos
    4. Un ejemplo real
    5. Uso de mailstat
    6. Usos del procmail para el Administrador del Sistema
    7. Conclusiones




 1 - Introducción.

1.1 - Qué es el Procmail?

Procmail es un filtro de correo, és decir, intercepta cada mensaje que llega a un usuario y lo distribuye en diferentes carpetas (folders) de entrada. Sería como tener diferentes INBOX, además de la que tenemos por defecto. Esto facilita mucho la clasificación del correo a personas que estan apuntadas a listas de correo, ofreciendo la posibilidad de tener un folder de entrada para cada lista en que se está suscrito, por ejemplo.

La manera como se usa el procmail es editando un fichero con un nombre especial, como ya veremos más tarde, y poniendo este fichero en nuestro directorio home. Este informe os introducirá, entre otras cosas, en las complejidades de escribir este fichero.

1.2 - Formato de un mensaje

Los mensajes se guardan uno tras otro y cada mensaje se podría separar en dos partes principales : información de routing e información del mail.

La sección de routing contiene información referente al camino que ha seguido el mensaje para llegar a su destinatario.

La sección del mail o mensaje asimismo tambien esta dividida en dos partes : cabecera y cuerpo.

La cabecera contiene la información de quien envía el mensaje, a quien va dirigido, el comentario o tema del mensaje, la version del programa de correo utilizado por el que envía el mail, si hay ficheros adjuntos... etc.

El cuerpo del mensaje contiene realmente el contenido del mensaje, y los posibles ficheros 'atachados'.

Ejemplo: Ejemplo de mail enviado desde Hades.udg.es a Speedy.udg.es.

Información del camino que ha seguido

From matas@hades.udg.es Wed May 21 10:24:24 1997
Received: from sun1.udg.es by speedy.udg.es; (5.65/1.1.8.2/10Apr95- 0953AM)
id AA18333; Wed, 21 May 1997 10:24:24 +0100
Received: from hades.udg.es (matas@hades.udg.es [130.206.124.48]) by sun1.udg.es
Received: from localhost (matas@localhost) by hades.udg.es (8.8.3/8.7.3) with S

Fecha en que se ha enviado:

Date: Wed, 21 May 1997 10:21:53 -0100 (GMT+1)

Información del mail: cabecera

From: David Matas Garcia
To: dm2933@speedy.udg.es
Subject: Aixo es una proba de mail
Message-Id: Mime-Version: 1.0

Cuerpo del mail:

Content-Type: TEXT/PLAIN; charset=US-ASCII
Esto es el contenido del mensaje.

Principales campos que aparecen en la cabecera.

Variables que normalmente permiten editar los editores de mails :

From: Quien envía el mail.
To: A quién va dirigido el mail.
cc: A quién se ha enviado copias del mail.
Subject: Comentario que pone el que envía el mail a fin que el receptor sepa de que trata el mail.

Campos que se definen cuando se tratan los mails

Normalmente los campos que definimos van predecidos por una X pero puede ser cualquier nombre que sirva después para tratar el mail.

  • Reply-to
    A quién se le ha hecho el reply.
  • X-Loop
    Se asigna tu propia dirección a fin que si se vuelve a recibir el mail se pueda rechazar.
  • Status
    Indica el estado en el que se encuentra el mail. Incorpora varios flags adicionales. Si este campo no existe, significa que el mail es nuevo. Puede tener varios valores:
    O - El receptor ha abierto el editor de mails y lo ha visto, pero no lo ha leido.
    R - Que el receptor ha leido el mail.
  • Sender
    Se usa para poner quien es realmente el que ha escrito el mail a la lista. Eso es porque cuando la lista emita el mail en el campo From: quedará la dirección de la propia lista.

2 - Instalación del Procmail

La instalación del procmail en el sistema es como cualquier otra instalación de una utilidad UNIX. La característica más importante del procmail, sin embargo, es que no hace falta ser root para instalarlo y usarlo, es decir, cada usuario de una máquina con cuenta puede instalarse su propio procmail y usarlo.

Por lo tanto, vemos que podemos instalar el procmail de dos formas :

A nivel de root. El procmail se instala en alguno de los directorios del sistema usados normalmente para instalar aplicaciones, por ejemplo, /usr/bin, y cualquier usuario puede usarlo (creando, como veremos más tarde con más detalle, un fichero en su directorio $HOME, cuyo nombre es .procmailrc. En este fichero habrá todos los filtros que el usuario aplicará a sus mensajes cuando estos le lleguen).

Una opción que tiene el usuario root es crear un fichero común de filtros, de tal manera que los mails destinados a todos los usuarios del sistema seran procesados por este fichero, previo a los filtros que el usuario especifique en su propio .procmailrc. Este fichero hay que ubicarlo en el directorio `etc' con el nombre de `procmailrc', es decir,

/etc/procmailrc

Hacer esto es análogo a definir un fichero profile común para todo usuario, a parte del profile que se pueda definir cada usuario.

Instalación de usuario. El procmail se instalará en el directorio que especifique el usuario, eso sí, previa modificación de los ficheros de configuración que se usan en la instalación.

Supongamos, pues, que el usuario Pepito se ha instalado el procmail en un directorio de su cuenta, supongamos el siguiente:

$HOME/bin

Para tal que el mail que llegue sea procesado por el procmail del usuario, hace falta crear un fichero especial en el directorio home del usuario, llamado .forward, especificando donde se encuentra el procmail y el login del usuario que lo ejecuta. Este fichero tiene el siguiente formato (todo en una línea seguida):

"| IFS=‘ ‘ && exec /directorio_desde_raiz/procmail -f- || exit 75 #login_name"

Seguiendo el ejemplo anterior, el fichero .forward tendría que tener el siguiente contenido:

"| IFS=‘ ‘ && exec /home/aupat/Pepito/bin/procmail -f- || exit 75 #Pepito"

Hay que recalcar que el fichero debe contener el texto en una sola línea. Si no se hace así, no funcionará.

El fichero .forward normalmente se usa para hacer desviar los mails que llegan a un usuario a otra máquina. Por ejemplo, el siguiente fichero .forward envía los mails que me llegan a la cuenta de la dirección de correo que tengo en morgan:

isjg6881@morgan.udg.es

En nuestro ejemplo sobre el procmail, este fichero lo que hace es enviar a la entrada de la orden procmail el mail que nos llega. Es decir, todos los mails que lleguen al usuario Pepito seran procesados por el procmail que se ha instalado en su cuenta, usando com fichero el .procmailrc que haya editado y dejado en su directori $HOME.

Alguien podría pensar que al poder ejecutar su procmail propio, el usuario podrá hacer cosas que atenten contra la seguridad del sistema, como podrían ser borrar ficheros de otros usuarios, o cosas parecidas, pero nada más allá que la realidad. El proceso procmail que se cree cuando el usuario recibe un mensaje será un proceso propiedad de el, no de root, y por lo tanto no podrá hacer nada que el no pueda hacer y root sí.

Detalles más precisos sobre la instalación del procmail los podreis encontrar en el paquete entero, que se puede bajar de la siguiente dirección:

ftp.informatik.rwth-aachen.de/pub/packages/procmail

El procmail fue creado por Stephen R. van den Berg. La última versión existente en el momento de finalizar este informe era la 3.16, con fecha de 11/04/97.

3 - Cómo se usa

Para que el procmail nos filtres los mensajes, tendremos que editar un fichero que se tendrá que decir .procmailrc. Los ficheros que empiezan con un punto en UNIX son ficheros ocultos. Por tanto, si se usa la orden ls para ver los ficheros que tenemos en el directorio home no veremos estos ficheros. Para poder ver los ficheros ocultos, hay que usar el flag -a (ls -a). El -a proviene de “all” (todos).

El uso del procmail pasa por la edición, como ya hemos dicho, del fichero .procmailrc. Para alguien que no haya visto nunca uno, el formato de este fichero puede parecerle algo mágico, y al mismo tiempo complicado. Por lo tanto, empezaremos con un pequeño ejemplo e iremos comentandolo y ampliándolo poco a poco.

3.1 - Fichero .procmailrc básico

Inicialmente, un fichero .procmailrc básico puede tener el siguiente contenido :

# .procmailrc
# variables de entorno del procmail
PATH=/usr/bin:/usr/local/bin
MAILDIR=$HOME/mail # El directori donde tendremos todos los folders
LOGFILE=$MAILDIR/logfile # Fichero de logs
SHELL=/bin/sh

# Poner el mail que llega de la lista de linux, al folder linux
:0:
* ^(From|To|Cc).*linux@hades
linux

No te preocupes, que no es tan difícil como parece. El fichero .procmailrc tiene dos partes bien diferenciadas: asignaciones (“assignments”) y recipientes (“recipes”). Las asignaciones establecen variables con nombres especiales que el procmail usa para saber donde tenemos los folders; esta es la primera parte. La parte realmente interesante es el recipiente que hay al final, y que define la acción a efectuar. Cualquier cosa precedido por un sostenido (#) es un comentario, y es ignorado por el Procmail.

Examinemos con más detalle cada una de las dos partes en que está formado el fichero.

3.1.1 Asignaciones

La sección de asignaciones informa al Procmail de donde podrá encontrar todo aquello necesario para funcionar correctamente, como los folders, o los programas que necesitará ejecutar. El conjunto de asignaciones que se incluye en el ejemplo acostumbra a ser suficiente para la gran mayoría de usuarios, aunque siempre se puede ampliar con más variables y asignaciones.

A continuación comentamos las asignaciones del ejemplo que hemos incluido. El formato de una asignación toma la forma nombre_de_variable=valor.

PATH=/bin:/usr/bin:/usr/local/bin

Esto le dice al Procmail donde tendrá que buscar los ejecutables, en caso que hagamos uso de ellos. Si las órdenes que usaremos ya se encuentran accesibles a través del PATH del shell, entonces no es necesario volver a definir el PATH.

MAILDIR=$HOME/mail

MAILDIR contiene la localización de los folders en que guardaremos el correo. $HOME contiene el path del directorio home del usuario, por lo tanto MAILDIR apunta al directorio mail de nuestro directorio home. El nombre del directorio puede variar, dependiendo del programa lector de correo que se use. Elm usa el “Mail” ; en cambio Pine usa el “mail”. Por lo tanto, conviene estar seguros de cual es el directorio que usa nuestro lector de correo.

LOGFILE=$MAILDIR/logfile

LOGFILE especifica el nombre de un fichero de logs, en el cual Procmail escribirá cualquier diagnóstico o mensajes de error al recibir los mensajes. También podríamos hacer que el Procmail no guardara esta información, simplemente especificando como a fichero de logs el /dev/null. Esto haría que cualquier mensaje de log creado por el Procmail, a efectos prácticos, fuera ignorado. También podríamos hacer (a modo de aperitivo y como una muestra de las cosas que se podrían llegar a hacer) que se creasen ficheros de log diarios, es decir, un fichero de log para cada día, usando la orden UNIX date:

LOGFILE=$MAILDIR/log.`date +%y-%m-%d`

Esto crearía ficheros de log con nombres como log.97-05-01, log.97-05-02,etc.
Los ficheros de log son útiles sobretodo para intentar encontrar errores, y tener un resumen de los mails que hemos recibido.

SHELL=/bin/sh

Esto define el shell que el Procmail usará para ejecutar las órdenes, si es que en el fichero .procmailrc hacemos uso de ellas.

3.1.2 Recipientes

Una vez repasadas las asignaciones más comunes, podemos pasar a analizar la parte más interesante: los recipientes. En los recipientes es donde se efectua el filtraje del mensaje que nos ha llegado, y es aquí donde las cosas se pueden llegar a complicar, dependiendo de aquello que queramos hacer.

El formato de un recipiente es el siguiente:

:0 [flags] [: [fitxer_lock] ]
cero o más condiciones
una línea conteniendo la acción a efectuar

De los flags y del fichero de lock hablaremos más tarde. Lo que nos interesa ahora es que si se cumplen las condiciones de la segunda línea, la acción de la tercera línea es ejecutada. Ahora volvamos a repasar el recipiente que hemos escrito anteriormente, el cual filtraba el correo que me llegaba de la lista de linux:

# Poner el mail que llega de la lista de linux, al folder linux
:0:
* ^(From|To|Cc).*linux
linux

La acción en este caso es bastante simple: “linux”, el nombre del folder donde se guardará el mensaje (fijaos que no hemos incluido el path del directorio donde está situado el folder. El Procmail usa la variable MAILDIR, la cual ya ha sido previamente incializada con el path donde tenemos los folders). La acción también podría haber sido una dirección e-mail a la cual rebotar el mensaje, (es decir, hacer un forward), o bien ejecutar una orden de las disponibles en UNIX, o bien también un bloque de ordenes. Veremos otros ejemplos de más complejidad más adelante.

La condición es la parte del recipiente que informa al Procmail de lo que tendrá que buscar en el mensaje. Las condiciones empiezan con un asterisco (*), y el resto de la expresión és un patrón a buscar. Si parte del mensaje coincide con el patrón buscado, luego se ejecutará la acción que viene a continuación. El patrón a buscar recibe el nombre de expresión regular. Traduciendo literalmente el patrón del ejemplo a lenguaje escrito, se podría decir como:

al empezar de la línia `From' o `Cc' o `To', seguido de cualquier número de caracteres cualquieras, seguido per `linux'

Cualquier mensaje que en su cabecera, en los campos `From', `To' o `Cc', contenga la palabra linux, la cual forma parte de la dirección de correo asociada a la lista, será tratado por la acción siguiente, es decir, guardado en el folder linux. Así de potente.

La mayoría de los ficheros .procmailrc tiene más de un recipiente, ya que no estamos limitados a uno solo, sino que podemos tener tantos como queramos. El funcionamiento normal, a menos que no lo cambiemos expresamente, será que Procmail se parará en el primer recipiente que procese satisfactoriamente el mensaje. Veremos más adelante como hacer que el mismo mensaje pueda ser procesado por varios recipientes.

La parte que cuesta más de entender, como es natural, es la expresión a partir de la cual se formula la condición. A continuación se explican lo que son las expresiones regulares, usadas en la elaboración de las condiciones de los recipientes.

3.2 Expresiones regulares

Para poder comprender las condiciones usadas en los recipientes que más tarde veremos, explicaremos con ejemplos lo que son las expresiones regulares, y su sintaxi.

Las expresiones regulares son expresiones que contienen caracteres con un significado especial, y que definen un patrón de frase. Al principio pueden resultar un poco crípticas, sobretodo si la expresión regular es larga y compleja.

Ante todo, cualquier carácter que no es un carácter especial se corresponde a sí mismo. Esto incluye letras, números y algunos signos de puntuación. Por ejemplo, la expresión regular...

casa

se corresponde con la cadena “casa”. Es importante recalcar que esta correspondencia es sensible a mayúsculas y minúsculas. Esta expresión no se correpondría con “Casa”, por ejemplo.

Un punto (.) se correponde con cualquier carácter excepto una nueva línea. Así pues, la expresión...

.asa grande

... aceptaría cadenas como “Casa grande”, “Pasa grande”, etc.

Cualquier carácter seguido de un asterisco (*) se correponde con el carácter repetido cero o más veces. Así, por ejemplo...

Casa* grande

... aceptaría cadenas como “Cas grande”, “Casa grande” o “Casaaaaa grande”.

Así, pues, una vez vistos los dos casos anteriores, la expresión...

.*

... se corresponde con cualquier carácter (el punto) repetido cero, una o más de una vez (el asterisco). És decir, cualquier cadena de número indeterminado de caracteres.

Tenemos otros modificadores, como el más (+) y el interrogante ( ?). El símbolo + precedido de un carácter se corresponde con el carácter una vez, o repetido más de una vez. Así, la expresión...

Casa+

... aceptaría “Casa”, “Casaa”, “Casaaa”, etc. El modificador ? se corresponde con nada o el carácter anterior. Así la expresión...

Casa?

... aceptaría las cadenas “Cas” y “Casa”.

Tambíen se pueden usar paréntesis para agrupar una expresión a usar por un modificador. Así, la expresión...

Ca(sa)+

... se correpondría con las cadenas “Casa”, “Casasasa”, etc.

Si un carácter en un patrón puede ser escojido de un grupo reducido de caracteres, se puede usar un carácter de clase. Por ejemplo:

Casa [1234]

... se correspondría con las cadenas “Casa 1”, “Casa 2”, “Casa 3” y “Casa 4”. Si el primer carácter de la clase es un sombrero (^), luego la expresión se correponde con cualquier carácter que no se encuentra dentro de la clase. Así, por ejemplo...

[^aeiou]+

... se correspondría con cualquier serie de uno o más caracteres, siendo estos caracteres no-vocales.

Otro operador disponible es la barra vertical ( | ). Se usa para hacer un or lógico entre dos o más expresiones. Así, por ejemplo...

Casa|Patio

... aceptaría las cadenas “Casa” y “Patio”, y ninguna más.

El último carácter que especial que comentaremos será el sombrero (^), y el símbolo de dólar ($). En este caso el carácter ^ entenderemos que no se encuentra dentro de una clase, y significa el principio de una linea. $ significa el final de una línea. Así, por ejemplo...

^To:

... se correponde con los caracteres “To:” al principo de una linea.

Los caracteres especiales que hemos comentado son los más usados en la elaboración de las condiciones de los recipientes.

Una vez vistas las expresiones regulares, pondremos unos cuantos ejemplo más que nos ilustraran su uso y la potencia del Procmail para filtrar mensajes y hacer con ellos lo que queramos.

3.3 Otros ejemplos

Al respecto de los ejemplos que vienen, supondremos que usamos las mismas variables de entorno que hemos puesto anteriormente.

3.3.1 - Uso del fichero de lock

Supongamos que estamos suscritos a la lista vbesp, relacionada con programación con Visual Basic. Nos interesa poner todos los mensajes provinentes de esta lista en un folder aparte. Los mensajes provinentes de esta lista llevan en la cabecera la siguiente linea de texto:

To: Lista de Visual Basic <vb-esp@ccc.uba.ar>

El texto inicial (“Lista de Visual Basic”) puede cambiar, ya que cada usuario pone el texto que quiere. En cambio, lo que sabemos seguro es que la dirección estará siempre, por lo tanto será esto lo que la nuestra condición tendrá que evaluar. Nuestra condición será “una linea empezando por `To:' y conteniendo `vb-esp'”. El recipiente quedaría así:

:0: # Usamos un fichero de lock
* ^To:.*vb-esp
vbesp

Es importante tener en cuenta que no se pueden poner comentarios en la línea de la condición, ya que el Procmail supondrá que forma parte de la expresión regular a evaluar.

Como muchos observareis, este recipiente no es muy fiable. Supongamos que una persona efectua un reply de un mensaje de la lista y envía el mensaje directamente a la persona a que responde, y envía una copia (cc, que proviene de Carbon Copy) a la lista. En este caso, la dirección estaría en una linea que empezaría por `cc:'. Por tanto, podemos reforzar el recipiente anterior modificando la condición de la siguiente forma:

:0: # Usamos un fichero de lock
* ^(To:|cc:).*vb-esp
vbesp

Ahora es un buen momento para hablar sobre el fichero de lock. Supongamos, por un momento, que nos llegan dos mensajes seguidos de la lista vb-esp. Es muy posible que se ejecuten dos copias del Procmail, y cada una de ellas probará de guardar el mensaje en el folder vbesp, con la cual cosa nos podemos encontrar que dos procesos intenten escribir en el mismo fichero. Usando un fichero de lock, el primer Procmail creará el fichero de lock y lo bloqueará hasta que el mensaje sea procesado, y luego lo desbloqueará. El segundo Procmail intentará crear el fichero de lock y verá que otro proceso lo tiene bloqueado, de forma que se esperará a que el primer Procmail lo desbloquee.

En un recipiente, el nombre del fichero de lock se especifica después del ` :0:'. En el ejemplo anterior, no hemos especificado ningun nombre de fichero. Esto hará que por defecto el nombre del fichero será `vbesp.lock' (el nombre del folder seguido de la extensión .lock).

3.3.2 - Enviando un mensaje a otras direcciones de correo (forward)

Supongamos ahora que tenemos un amigo que se llama Juan que nos envía mensajes referentes al tema `multimedia', y que nos interesa que estos mensajes se guarden en otra dirección de correo que tenemos en otra máquina. Por tanto, hemos de hacer que la condición mire que el mensaje proviene de `Juan', y que el tema es `multimedia' :

:0
* ^From.*Juan
* ^Subject:.*multimedia
! jordi@redestb.es

Dos cosas a explicar:

- Hacer un forward se consigue mediante el símbolo `!' seguido de la dirección.

- Fijemonos aquí que no usamos fichero de lock (no tenemos los dos puntos después del `:0'). Esto es debido a que no nos hace falta en este caso, ya que simplemente lo que hacemos es desviar el mensaje y hacer que se guarde en otra dirección de correo.

3.3.3 - Bloques de acciones

Supongamos, seguiendo el ejemplo anterior, que no solo nos interesa rebotar el mensaje a la otra dirección, sino que tambien nos interesa imprimir el mensaje, sin que se nos quede guardado el mensaje en ningun folder. En este caso, pues, queremos hacer dos cosas, y por tanto necesitamos ejecutar dos acciones. Para hacerlo usaremos una técnica que se llama indentación. El recipiente quedaría modificado de la siguiente forma:

:0
* ^From.*Juan
* ^Subject:.*multimedia
{
      :0 c
      ! jordi@redestb.es

      :0
      | lpr -Pacsps
}

En vez de una sola acción usamos un bloque indentado, entre llaves. Este bloque representa como un segundo fichero .procmailrc, en el cual podemos incluir cualquier número de recipientes que se procesaran solo si se ha procesado el recipiente padre.

Dos cosas a explicar:

- El primer recipiente de dentro del bloque hace rebotar el mail a la otra dirección. Fijémonos que hemos incluido el flag `c'. La `c' significa copiar el mail, de forma que el próximo recipiente también pueda procesar el mail, ya que por defecto el mensaje se pierde después del primer recipiente que lo procesa.

- Para redirigir el mensaje a la entrada de una orden se usa el símbolo de barra vertical `|' (una pipe). El mensaje es enviado a través de una pipe a la entrada de la orden lpr, la cual imprimirá el mensaje en la impresora “acsps”.

3.3.4 - Recipientes que dependen de otros recipientes.

Otra forma de hacer el ejemplo anterior, es hacer un recipiente que mire si el mensaje proviene de Juan y es sobre multimedia, y si es así que envíe el mensaje a la otra dirección, y acto seguido, tener otro recipiente que mire si el primero se ha procesado. Si es asi, el segundo recipiente también procesará el mensaje. Para hacer esto se usa el flag `A':

:0 c
* ^From.*Juan
* ^Subject:.*multimedia
! jordi@redestb.es

:0 A
| lpr -Pacsps

El flag `A' lo que hace es mirar si el anterior recipiente ha sido procesado. En este caso no tenemos línea de condición, ya que el flag ya hace de condición. (Existe otro flag, `E', que hace lo inverso, mirar si el recipiente anterior no ha sido procesado.

3.3.5 - Archivar mensajes

Supongamos que nos interesa archivar los mensaje que nos llegan de la lista vbesp en un fichero zipado, para tenerlos todos guardados. Para hacer esto podemos enviar el mensaja a la entrada de la orden gzip:

:0 bc: fitxer.lock
* ^(To|From|cc).*vb-esp@ccc\.uba\.ar
| gzip >> archivo-vb.gz

Los mensajes se iran acumulando al final del fichero archivo-vb.gz

Dos cosas a explicar:

- Aquí usamos el flag `b', que significa que solo archivaremos el cuerpo del mail, es decir, descartamos la cabecera (`b' viene de body, el contenido del mensaje). También usamos el flag `c', ya que nos interesa también recibir el mensaje en el correspondiente folder (el recipiente que lo hace vendría después).

- A la condición hacemos coincidir la dirección entera. Ya que la dirección de correo contiene puntos, y el punto es un carácter especial, para hacer que el carácter punto sea considerado como otro carácter más usamos una barra invertida (\).

3.3.6 Hacer un reply de un mensaje cuando estamos de vacaciones

Ahora un ejemplo más complicado. Supongamos que estamos suscritos a varias lista de correo, y que queremos (durante todo el tiempo que estamos fuera de vacaciones) contestar a todos con un texto informativo de nuestra absencia y del día que volveremos a conectarnos.

Para hacer esto nos hemos de asegurar primero de todo de no hacer un reply a mensajes que nos provienen de una lista, porque los volveríamos a recibir, y así sucesivamente, y podría ser desastroso. La forma más segura de evitar esto es incluir el recipiente después de todos los recipientes que tratan los mensaje provinentes de listas de correo. También hay que evitar hacer replys a los mensajes que nos envía el deamon de mail. Para hacer esto incluiremos la expresión FROM_DAEMON, la cual detecta si el mensaje proviene del daemon de mail (por ejemplo, cuando enviamos un mail y nos equivocamos de dirección, recibimos un mensaje donde se nos informa de este hecho. Este mensaje nos lo ha enviado el daemon de mail). Para ver a qué equivale esta expresión, consultad la ayuda del man.

:0 Whc: vacaciones.lock
* !^FROM_DAEMON
* !^X-Loop: jordi@hades.udg.es
| (formail -r -A”X-Loop: jordi@hades.udg.es”;\
   cat vacaciones.msg)|/usr/lib/sendmail -t

Cosas a comentar:

- El símbolo de admiración (!) sirve para negar la condición. En este caso la condición es “todos aquellos mensajes que no provienen del daemon de mail”.

- Aquí se usan dos nuevos flags:
W. Esperar a que el proceso que se ejecuta en la acción acabe, suprimiendo cualquier mensaje de error.
h. La acción procesará solo la cabecera del mensaje.
- Aquí se usa la orden formail (mail formatter) la cual se usa para tratar de forma avanzada cualquier de las partes de que está formado un mensaje. En el ejemplo usamos la orden con dos flags:
r. Genera un cabecera de auto-reply. Es decir, todos los campos de l cabecera del mensaje que tratamos son borrados (todos menos X-Loop) y generados de nuevo con los campos por defecto que se generan cada vez que hacemos un reply a un mensaje.
A. Añade una nueva línea en la cabecera, con el texto que se incluya a continuación.

- La acción escrita ocupa más de una línea. Como que las acciones solo pueden ocupar un linea se usa una barra invertida al final (\), la cual cosa nos permite escribir la acción en dos líneas.

La acción, como se puede comprobar, lo que primero hace es generar una nueva cabecera para el mensaje que enviaremos. Acto seguido efectuamos un cat del mensaje que tenemos en nuestra cuenta, con el texto a enviar (las diferentes acciones las separamos con puntos y comas), y el resultado de todo esto lo enviamos a través de una pipe a la orden sendmail, la cual nos enviará el mensaje. Y a quien lo enviaremos ? Pues a las direcciones especificadas en la cabecera en las lineas To:, Cc: y Bcc: (esto es así gracias al flag -t del sendmail). En nuestro caso, en la linea To: habrá la dirección de la persona que nos ha enviado el mensaje.

De ejemplos se podrían incluir muchos más, algunos de extrema dificultad. Como se puede comprobar, para procesar mensajes, hacer auto-replys, tratar cadenas, etc. necesitamos tener conocimientos sobre ordenes como formail, sendmail, sed, awk (los recipientes que usan estas dos, si no se conocen bien, pueden resultar un auténtico jeroglífico indescifrable), etc. Una completa información sobre cada una de estas órdenes se puede encontrar siempre en la ayuda del sistema.

4 - Un ejemplo real

Para tal de completar los conocimientos que hemos adquirido sobre el procmail, a continuación comentamos el fichero .procmailrc usado por uno de nosotros, el cual nos muestra algunos usos más de la orden formail, y que contienen algunos ejemplos buenos y útiles de recipientes, necesarios sobretodo cuando se recibe mucho correo provinente de diferentes listas de correo.

#Procmailrc. Versión 3.16
# -------------------------------------------------------------------------------------------------------
# Asignaciones
# -------------------------------------------------------------------------------------------------------
# ORGMAIL (Original Mail), indica cual es el folder por defecto en el cual recibiremos
# el correo. Este folder recibe el nombre común de INBOX, y normalmente se
# encuentra en el directorio /var/spool/mail. El nombre real del folder es nuestro login.
# En este caso usamos la variable de entorno LOGNAME, la cual contiene nuestro
# login.
# -------------------------------------------------------------------------------------------------------

ORGMAIL=/var/spool/mail/$LOGNAME

# -------------------------------------------------------------------------------------------------------
# Directorio donde se guarda el correo y estan todos los folders ($HOME/mail usado
# por pine).
# -------------------------------------------------------------------------------------------------------

MAILDIR=$HOME/mail

# -------------------------------------------------------------------------------------------------------
# Fichero de logs. Cada vez que recibimos un mail se guardará en este fichero
# información sobre el mensaje (a qué folder ha ido a parar, mensajes de error, ect). El
# fichero de log es muy útil para encontrar errores y consultar estadísticas de los mails
# que nos lleguen. Más tarde veremos como se pueden obtener estas estadísticas.
# -------------------------------------------------------------------------------------------------------

LOGFILE=$MAILDIR/logfile

# -------------------------------------------------------------------------------------------------------
# Fichero de zipados. Aquí guardaremos todos los ficheros .gz, simplemente para una
# organización mejor de nuestro directorio.
# -------------------------------------------------------------------------------------------------------

ZIPATS=$MAILDIR/zipats

# -------------------------------------------------------------------------------------------------------
# VERBOSE es una variable de entorno que nos permite definir el grado de detalle
# (completo o sencillo) para los mensajes de error y logs generados por el Procmail.
# “no” o “off” dejan el nivel de detalle a sencillo. “Yes” o “on” dejan el nivel de detalle
# a completo.
# -------------------------------------------------------------------------------------------------------

VERBOSE=no

# -------------------------------------------------------------------------------------------------------
# Recipientes
# -------------------------------------------------------------------------------------------------------
# -------------------------------------------------------------------------------------------------------
# El primer recipiente de todos tendría que ser un recipiente que impidiese que
# recibiéramos el mismo mensaje duplicado, triplicado, etc... O sea, evitar que un
# mismo mensaje nos llegue más de una vez. Esto pasa muy a menudo, sobretodo
# cuando una persona envía el mensaje a diferentes listas de correo, y nosotros estamos
# apuntados a ellas. El siguiente recipiente usa la orden formail para filtrar el mensaje,
# mirar qué ID contiene (todos los mensaje tienen un ID único) y guardar este ID en un
# fichero caché que como mucho podrá tener un tamaño de 8K. Si el mensaje nos llega
# más de una vez, el ID estará en el fichero caché, y la orden acabará satisfactoriamente
# (formail devolverá true) la cual cosa hace que el mensaje no sea procesado por los
# posteriores recipientes. Si el mensaje es nuevo, se archiva el ID y la orden devolverá
# false, y esto hará que el mensaje pase hacia abajo y sea procesado por el siguiente
# recipiente.
# -------------------------------------------------------------------------------------------------------

:0 Wh: msgid.lock
|formail -D 8192 $MAILDIR/msgid.cache

#-----------------------------------------------------------------------
# Filtrar unsubscribes. Esto es lo primero que uno tiene que hacer cuando está suscrito a
# alguna lista: que le lleguen los típicos mensajes de la gente que se quiere desuscribir y
# que, sea por descuido o por ignorancia, la persona que los envía lo hace a la lista de
# correo, y no al servidor. El siguiente recipiente comprueba que en el cuerpo del
# mensaje haya el texto que la gente acostumbra a poner en estos mensajes. Si el
# mensaje es procesado, lo que haremos será guardar en un fichero gz el nombre de la
# persona que nos lo envía y la fecha.
#
# Nuevos flags usados:
#
# B La condición se evalua sobre el cuerpo del mensaje.
#
# W Esperar que el proceso que se ejecuta en la acción finalize.
#
# Esta vez usaremos el formail con el flag `x' seguido del campo de la cabecera quen os
# interesa filtrar (From:).
# -----------------------------------------------------------------------

:0 hBw: zipant.lock
* ^.*(((un)*su[bs]*cri[bm]e) | (un)*sub)
|formail -x From: | gzip >> $ZIPATS/RCsUN.gz && \
;date +%y-%m-%d | gzip >> $ZIPATS/RCsUN.gz

# -------------------------------------------------------------------------------------------------------
# También nos interesa comprobar que el mensaje sea un RCPT. Existen programas de
# correo que permiten hacer que el usuario, al recibir un
# mail, automáticamente envíe otro incluyendo un texto corto, donde pone que ha
# recibido el mail. Es decir, un mensaje de confirmación de recibida del mail. Muchos
# usuarios tienen mal configurada esta opción, de forma que el mensaje es enviado a la
# lista, lo que significa que puede pasar (y sigue pasando) que una buena parte de los
# mensajes que se reciben en una lista son RCPT's, los cuales no contienen ninguna
# pregunta ni contenido. El recipiente comprobará si el mensaje es un RCPT.
#
# Nuevos flags usados:
#
# H La condición se evalua sobre la cabecera del mensaje, solamente.
# -------------------------------------------------------------------------------------------------------

:0 hHw: zipant.lock
* ^.*RCPT
|formail -x From: | gzip >> $ZIPATS/RCsUN.gz && \
;date +%y-%m-%d | gzip >> $ZIPATS/RCsUN.gz

# -------------------------------------------------------------------------------------------------------
# Cojo el From y el Subject del mensaje, siempre que no sea un mensaje del daemon, y
# los zipo, dentro de resumen.gz. Así dispongo de un resumen de lo que me ha llegado
# cuando me conecto. Para leer un fichero que está gunzipado, se usa la orden less.
# -------------------------------------------------------------------------------------------------------

:0 hwc:
* !^FROM_DAEMON
|formail -x From: -x Subject: | gzip >> $ZIPATS/resum.gz

#-----------------------------------------------------------------------
# Lista de Visual Basic española
# Los mails que van a la lista de visual basic, al folder vbesp
#-----------------------------------------------------------------------

:0:
* ^(To|From|cc).*vb-esp@ccc\.uba\.ar
vbesp

#----------------------------------------------------------------------
# Lista de Microsoft Access
# Los mails que van a la lista de Access, al folder access
#-----------------------------------------------------------------------

:0:
* ^(To|From|cc).*@PEACH\.EASE\.LSOFT\.COM
access

# -------------------------------------------------------------------------------------------------------
# Lista de Visual Basic VB-L.
# Los mensajes de esta lista vienen en formato DIGEST. Es decir, en vez de recibir los
# mails individualmente a medida que la gente los va enviando, los mensajes se
# reciben todos juntos en uno sólo. La frecuencia en que se reciben los mails en este
# tipo de listas es menor (en el caso de VB-L, es de un mensaje cada dos semanas).
# Como que leer y clasificar el mail en estos casos es difícil, normalmente las listas de
# correo permiten que el usuario envíe una petición al servidor, para cambiar esta
# configuración y recibir los mensajes individualmente. En el caso de VB-L, esto no es
# así.
# El recipiente siguiente coge el mensaje provinente de esta lista y lo separa en los
# diferentes mensajes que contiene, y los guarda en el folder VB-L. Para hacerlo se usa
# la orden formail con el parámetro s (split). El +1 quiere decir que no queremos
# guardar el primer mail que contiene el digest, ya que este mail contiene siempre un
# resumen de los mails que contiene el digest, y no nos interesa guardarlo.
# -------------------------------------------------------------------------------------------------------

:0:
* ^(To|From|cc).*vb-l@usa\.net
* ^Subject:.*DIGEST
|formail +1 -s >> $MAILDIR/VB-L

#----------------------------------------------------------------------
# Lista de correo de Linux
# Los mensajes que me llegan de la lista de linux, al folder linux
#-----------------------------------------------------------------------

:0:
* ^(To|From|cc).*linux@hades\.udg\.es
linux

#----------------------------------------------------------------------
# Lista de correo de procmail
# Los mensajes que me llegan de la lista de procmail, al folder procmail
#-----------------------------------------------------------------------

:0:
* ^(To|From|cc).*@Informatik\.RWTH-Aachen\.DE
procmail

# Fin .procmailrc

Como se puede comprobar, las posibilidades que nos ofrece el Procmail son ilimitadas, ya que podemos usar cualquier orden de UNIX en nuestros recipientes. Para poner un ejemplo, encontramos un usuario en Internet que explicaba que los mails que cumplían una determinada condición los enviaba a través de una pipe a un script, creado por el mismo, hecho en perl. El script lo que hace es coger el mensaje del mail y pasarlo a formato html, y el resultado redireccionarlo a un fichero. De esta forma tenía automáticamente el mail en formato html, listo para ser visualizado por cualquier browser.

Procmail sólo tiene un límite, y es el límite que se pretenda establecer el que lo usa. Está claro que si apenas recibimos correo no le encontraremos ninguna utilidad. Todo depende de las necesidades de cada uno.

5 - Uso de mailstat

Como ya hemos dicho repetidamente, estableciendo la siguiente variable en la sección de asignaciones...

LOGFILE=$MAILDIR/logfile

... hacemos que se cree un fichero de logs donde se guarda la información referente a los mails que recibimos, y mensajes de error. Pues bien, con el paquete del Procmail viene un script, creado por el autor del Procmail mismo, el cual coge el fichero de logs y nos muestra un resumen del correo que nos ha llegado, a donde ha ido a parar, etc.

Antes de usar el mailstat, veamos como es este fichero de logs de ejemplo:

From owner-access-l@PEACH.EASE.LSOFT.COM Mon May 12 15:48:52 1997
Subject: Access 2 KB on Win95
Folder: access 1843
From MAILER-DAEMON@hades.udg.es Mon May 12 15:54:51 1997
Subject: Returned mail: User unknown
Folder: /var/spool/mail/jordi 2803
From linux-owner@hades.udg.es Mon May 12 17:00:21 1997
Subject: Re: Servidor X
Folder: linux 2554
From vogelke@c17mis.region2.wpafb.af.mil Mon May 12 17:25:18 1997
Subject: Re: Use of procmail as System Administrator
Folder: /var/spool/mail/jordi 1743
From linux-owner@hades.udg.es Mon May 12 17:28:11 1997
Subject: Re: Algunas preguntillas
Folder: formail -D 8192 /home/aeigi/jordi/mail/msgid.cache 1211
From owner-vb-esp@ccc.uba.ar Mon May 12 17:43:06 1997
Subject: (VB-ESP) Unsubscribme vb-esp
Folder: formail -k -x From: | gzip >> $ZIPATS/RCsUN.gz && date +%y-%m 1173

Como se puede comprobar, cada vez que se recibe un mensaje se guarda automáticamente en el fichero de logs la siguiente información:

  • quién lo ha enviado (From)
  • la fecha en que recibimos el mensaje
  • el tema del mensaje
  • la acción que se ha llevado a término por parte del procmail
  • los bytes que ocupaba el mensaje

A partir de ahora es cuando entra en juego mailstat. La sintaxis de mailstat es:

mailstat [-flags] fitxer_log

Suponiendo que el fichero se llama logfile, una ejecución simple sería...

mailstat logfile

y a continuación se muestra una posible salida:

Total Number Folder
----- ------ ------
13422 5 /var/spool/mail/jordi
14445 6 access
2935 2 formail -D 8192 /home/aeigi/jordi/mail/msgid.cache
23144 9 linux
15446 5 procmail
7546 4 vbesp

Esta salida nos informa que, por ejemplo, hemos recibido 6 mensajes provinentes de la lista de Access, que se han guardado en el folder access y que en total ocupaban 14445 bytes. O también que hemos recibido dos mensajes repetidos, que el recipiente correspondiente se ha encargado de filtrar.

Es interesante ver cual es el uso de los principales flags que incorpora mailstat:

-k Mantener el fichero de logs intacto.

Por defecto, después de ejecutar la orden mailstat, se crea un fichero log.old con el contenido del fichero log, y se deja el fichero de log original a 0 bytes. Con el flag k podemos hacer que el fichero de log original no quede modificado.

-l Salida ampliada

Si ponemos este flag, además se nos muestra una columna indicando una mediana de bytes por folder. Poniendo por caso el ejemplo anterior, haciendo...

mailstat -l logfile

... tendríamos la siguiente salida:

Total Average Number Folder
----- ------- ------ ------
13422 2684 5 /var/spool/mail/jordi
14445 2407 6 access
2935 1467 2 formail -D 8192 /home/aeigi/jordi/mail/msgid.cache
23144 2571 9 linux
15446 3089 5 procmail
7546 1886 4 vbesp

- o Usar el fichero .old

Con este flag podemos consultar el fichero .old. Por ejemplo, haciendo...

maisltat -o logfile

... obtendríamos la salida correspondiente al fichero logfile.old.

- s Modo silencioso

Cuando al ejecutar mailstat, el fichero de log tiene 0 bytes, eso quiere decir que desde la última vez que hemos usado el script no nos ha llegado ningun mail. Si esto es así, se producte la siguiente salida:

No mail arrived since 24/05/97 11:00:23

Si usamos el flag -s, al ejecutar la orden no saldrá nada por pantalla.

Una forma típica de usar el mailstat es llamándolo desde el .profile. De esta forma, cuando entramos en la cuenta automáticamente vemos un resumen del correo que hemos recibido mientras estábamos desconectados.

6 - Usos del procmail para el Administrador del Sistema

Como hemos visto, el Procmail lo puede usar cualquier usuario, tan solo editando el fichero .procmailrc y colocándolo en el home de su cuenta. A continuación ponemos un ejemplo de uso del Procmail a nivel del Administrador del Sistema. El ejemplo consiste en crear una lista de distribución de correo.

Para tal de crear una lista de correo, hacen falta dos direcciones: la dirección de la lista (donde se envían los mensajes) y la dirección del servidor (donde se envían las peticiones de suscribirse, etc). Para poder tener dos direcciones, lo que se hace normalmente es incluir dos alias en el fichero /etc/aliases. Por ejemplo, imaginemos que la dirección de la lista se ha de llamar hardware@nombre.dominio, y la del servidor hardware-request@nombre.dominio. Se incluirían las dos siguientes entradas:

hardware: | /bin/procmail -m /etc/procmailrcs/procmailrc1
hardware-request: | /bin/procmail -m /etc/procmailrcs/procmailrc2

Cualquier mensaje que fuese dirigido a hardware@nombre.dominio sería filtrado por procmail con el fichero rc procmailrc1. Y lo mismo referente a la dirección del servidor.

Aquí ponemos un resumen de las tareas que tendría que realizar cada fichero rc. Por ejemplo, el fichero correspondiente a la dirección de la lista:

  • Controlar mails muy grandes.
  • Repartir el mail a todos los sucritores, evitando “ringing mail” (que un mensaje viaje indefinidamente entre la lista y la persona que envía el mensaje).
  • Archivar los mails que lleguen, de caras a implementar los digests. Enviar el digest a todos aquellos que lo tengan así configurado.

Y en referencia al servidor de la lista:

  • Gestión de suscripciones/desuscripciones.
  • Controlar personas non-gratas (usuarios que no puedan suscribirse porque son de un dominio determinado, etc).
  • Permitir configurar las opciones de cada usuario suscrito (enviar o no enviar acknowledges, si se quiere recibir los mensajes en modo digest o no, recibir una copia del mensaje que se envía, etc).
  • Permitir consultar los usuarios que estan suscritos.
  • Permitir recibir los mails archivados de meses pasados.

A continuación se incluyen dos ejemplos que implementan algunas de las tareas que hemos puesto. El primero comprueba que el mensaje no sea más grande de 100 K. Si es asi, es suprimido:

:0
* > 100000
/dev/null

El segundo implementa un servidor muy básico de ficheros. En el ejemplo se supone que los ficheros a enviar se encuentran en el directorio $HOME/mail/fileserver. Para poder recibir el fichero, en el subject del mensaje se tiene que poner “send file nombre_de fichero”.

:0
* ^Subject: send file [0-9a-z]
* !^X-Loop: jordi@hades.udg.es
* !^Subject:.*Re:
* !^FROM_DAEMON
* !^Subject: send file .*[/.]\.
{
      MAILDIR=$HOME/mail/fileserver

      :0 fhw
      * ^Subject: send file \/[^ ]*
      | formail -rA "X-Loop: jordi@hades.udg.es"

      FILE="$MATCH"

      :0 ah
      | cat - ./$FILE 2>&1 | $SENDMAIL -oi -t
}

7 - Conclusiones

Como habreis podido comprobar, el procmail es una herramienta excelente para poder organizar los mensajes que se reciben en un entorno Unix. Además, para un forofo de las listas de correo (yo mismo, por ejemplo) me atrevería a decir que es una herramienta indispensable.

Espero que este trabajo os haya servido para descubrir esta utilidad (a los que no la conocíais) y para ampliar vuestros conocimientos sobre ella (a los que sí ya la habíais usado).

Un saludo.



*****************************************
Jordi Garcia Busquets
jordi@hades.udg.es
Estudiante de 3º de Informática de Gestión
Universidad de Girona. Catalunya. España
*****************************************

ir al índice