El formato de correo electrónico Maildir es una forma común de almacenar mensajes de correo electrónico en un sistema de archivos , en lugar de en una base de datos. A cada mensaje se le asigna un archivo con un nombre único, y cada carpeta de correo es un directorio del sistema de archivos que contiene estos archivos. Maildir fue diseñado por Daniel J. Bernstein alrededor de 1995, con el objetivo principal de eliminar la necesidad de que el código del programa maneje el bloqueo y desbloqueo de archivos mediante el uso del sistema de archivos local. [1] El diseño de Maildir refleja el hecho de que las únicas operaciones válidas para un mensaje de correo electrónico son su creación, eliminación o cambio de estado de alguna manera.
Un directorio Maildir (a menudo llamado Maildir
) normalmente tiene tres subdirectorios llamados tmp
, new
, y cur
. [2]
tmp
subdirectorio almacena temporalmente los mensajes de correo electrónico que se encuentran en proceso de envío. Este subdirectorio también puede almacenar otros tipos de archivos temporales.new
subdirectorio almacena mensajes que se han entregado, pero que aún no han sido vistos por ninguna aplicación de correo.cur
subdirectorio almacena mensajes que ya han sido vistos por las aplicaciones de correo. [3]Sam Varshavchik, el autor del Courier Mail Server y otros programas, definió la extensión Maildir++ [3] [4] para el formato Maildir con el fin de admitir subcarpetas y cuotas de correo. Los directorios Maildir++ contienen subdirectorios con nombres que comienzan con un '.' (punto) que también son carpetas Maildir++. La extensión cumple con la especificación original de Maildir, que permite subdirectorios además de tmp , new y cur .
Un agente de entrega de correo es un programa que entrega un mensaje de correo electrónico en un Maildir. El agente de entrega de correo crea un nuevo archivo con un nombre de archivo único en el tmp
directorio. [5] [6] [3] En el momento de su invención, garantizar nombres de archivo únicos de manera eficiente era difícil. El algoritmo original de qmail [1] para nombres únicos era:
stat()
informa que el nombre del archivo existe, espere dos segundosEn 2000, el autor de qmail recomendó en una especificación actualizada [5] añadir el valor de un contador por proceso al PID, cuyo valor debería incrementarse después de cada entrega. Se abandonó la recomendación de limitar la velocidad de "esperar dos segundos".
En 2003, las recomendaciones se modificaron aún más para exigir que, en lugar del PID y el contador, se creara la parte central del nombre del archivo "concatenando suficientes de las siguientes cadenas para garantizar la unicidad", incluso ante múltiples entregas simultáneas al mismo maildir desde uno o más procesos: [7]
- # n , donde n es (en hexadecimal) la salida de la
unix_sequencenumber()
llamada al sistema del sistema operativo, que devuelve un número que aumenta en 1 cada vez que se llama, comenzando desde 0 después del reinicio.- X n , donde n es (en hexadecimal) la salida de la
unix_bootnumber()
llamada al sistema del sistema operativo, que informa la cantidad de veces que se ha iniciado el sistema. Junto con #, esto garantiza la unicidad; desafortunadamente, la mayoría de los sistemas operativos no admitenunix_sequencenumber()
yunix_bootnumber()
.- R n , donde n es (en hexadecimal) la salida de la
unix_cryptorandomnumber()
llamada al sistema del sistema operativo o una fuente equivalente, como/dev/urandom
. Desafortunadamente, algunos sistemas operativos no incluyen generadores de números aleatorios criptográficos.- En n , donde n es (en hexadecimal) el número de inodo de UNIX de este archivo. Desafortunadamente, los números de inodo no siempre están disponibles a través de NFS .
- V n , donde n es (en hexadecimal) el número de dispositivo UNIX de este archivo. Lamentablemente, los números de dispositivo no siempre están disponibles a través de NFS. (Los números de dispositivo tampoco son útiles con el sistema de archivos UNIX estándar: un directorio de correo debe estar dentro de un único dispositivo UNIX para que
link()
yrename()
funcionen).- M n , donde n es (en decimal) el contador de microsegundos del mismo
gettimeofday()
utilizado para la parte izquierda del nombre único.- P n , donde n es (en decimal) el ID del proceso.
- Q n , donde n es (en decimal) el número de entregas realizadas por este proceso.
Este algoritmo de 2003 fue criticado [8] en 2006 por ser innecesariamente complejo por Timo Sirainen , el creador de Dovecot .
A partir de noviembre de 2023, el autor de qmail, Daniel Bernstein , no había realizado más cambios en las recomendaciones de generación de nombres de archivo de 2003. [9] En los sistemas POSIX modernos, los archivos temporales se pueden crear de forma segura con la mkstemp
función de biblioteca C.
El proceso de entrega almacena el mensaje en el maildir creando y escribiendo en , y luego moviendo este archivo a . El movimiento se puede hacer usando , que es atómico en muchos sistemas. [10] Alternativamente, se puede hacer vinculando firmemente el archivo a y luego desvinculando el archivo de . Cualquier archivo restante eventualmente será eliminado. Esta secuencia garantiza que un programa de lectura de maildir no verá un mensaje escrito parcialmente. Puede haber múltiples programas leyendo un maildir al mismo tiempo. Van desde agentes de usuario de correo (MUAs), que acceden directamente al sistema de archivos del servidor, a través de servidores de Protocolo de acceso a mensajes de Internet o Protocolo de oficina postal que actúan en nombre de MUAs remotos, a utilidades como biff y rsync , que pueden o no estar al tanto de la estructura de maildir . Los lectores nunca deben buscar en .tmp/uniquefilename
new/uniquefilename
rename
new
tmp
tmp
Cuando un proceso de lectura de maildir consciente (ya sea un servidor POP o IMAP , o un agente de usuario de correo que actúe localmente) encuentra mensajes en el new
directorio, debe moverlos a cur
. Es solo un medio para notificar al usuario "tienes X mensajes nuevos". [11] Este movimiento debe realizarse utilizando el sistema de archivos atómico rename()
, ya que la técnica alternativa de vincular y luego desvincular no es atómica y puede dar como resultado mensajes duplicados. En esta etapa, se agrega un sufijo informativo a los nombres de archivo. Consiste en dos puntos (para separar la parte única del nombre de archivo de la información real), un "2", una coma y varios indicadores . El "2" especifica la versión de la información que sigue a la coma. "2" es la única versión especificada oficialmente actualmente, siendo "1" una versión experimental. La especificación define indicadores que muestran si el mensaje ha sido leído, eliminado, etc.: la letra inicial (mayúscula) de "Aprobado", "Respondido", "Visto", "Enviado a la papelera", "Borrador" y "Marcado". [7] Las aplicaciones a menudo optan por complementar este conjunto muy limitado de indicadores, por ejemplo, notmuch [12] ofrece sincronización de indicadores además de indicadores arbitrarios definidos por el usuario, [13] mientras que Dovecot usa letras minúsculas para que coincidan con 26 palabras clave IMAP, [6] que pueden incluir palabras clave como $ MDNSent o indicadores definidos por el usuario.
Aunque Maildir fue pensado para permitir su uso sin bloqueos, en la práctica algunos programas que utilizan Maildirs también utilizan bloqueos, como Dovecot. [14]
El estándar Maildir sólo se puede implementar en sistemas que aceptan dos puntos en los nombres de archivo. [15]
Los sistemas que no permiten el uso de dos puntos en los nombres de archivo (entre ellos, Microsoft Windows y algunas configuraciones de Novell Storage Services ) pueden utilizar un separador alternativo no estándar, como ";" o "-". A menudo, resulta trivial aplicar parches en software libre y de código abierto para que utilice un separador diferente. [16]
Como actualmente no hay un acuerdo sobre qué carácter debería ser este separador alternativo, pueden surgir dificultades de interoperabilidad entre los distintos programas que admiten Maildir en estos sistemas. Sin embargo, no todo el software relacionado con Maildir necesita saber cuál es el carácter separador, porque no todo el software relacionado con Maildir necesita poder leer o modificar los indicadores de un mensaje ("leído", "respondido", etc.); el software que simplemente envía a un Maildir o archiva mensajes antiguos de este basándose únicamente en la fecha, debería funcionar sin importar qué separador se esté utilizando. Si solo el MUA necesita leer o modificar los indicadores de los mensajes, y solo se utiliza un MUA, entonces se pueden utilizar separadores alternativos no estándar sin problemas de interoperabilidad.
Todos estos problemas son bastante inútiles. Solo el primer paso es lo que realmente garantiza que los correos no se sobrescribirán, el resto simplemente suena bien. Aunque pueden detectar un problema de vez en cuando, no ofrecen protección garantizada y con la misma facilidad pasarán nombres de archivos duplicados y sobrescribirán los correos existentes. El paso 2 no tiene sentido porque hay una condición de carrera entre los pasos 2 y 3. La combinación PID/host por sí sola ya debería garantizar que nunca encuentre dicho archivo. Si es así, algo está roto y la comprobación stat() no ayudará ya que otro proceso podría estar haciendo lo mismo al mismo tiempo, y usted termina escribiendo en el mismo archivo en tmp/, causando que el correo se corrompa.¶ En el paso 4 el link() fallaría si ya existiera un archivo idéntico en Maildir, ¿cierto? Incorrecto. El archivo puede que ya haya sido movido al directorio cur/, y dado que puede contener cualquier número de indicadores para entonces ya no puede comprobar con un simple stat() si existe o no.¶ Se señaló que el paso 2 era útil si el reloj se hubiera movido hacia atrás. Sin embargo, esto no da ninguna garantía de seguridad real porque ya podría existir un nombre de archivo base idéntico en cur/. Además, si el sistema se acaba de reiniciar, el archivo en tmp/ probablemente podría incluso sobrescribirse de forma segura (asumiendo que no se haya enlazado ya a new/).¶ Entonces, realmente, todo lo que es importante para no sobrescribir correos en su Maildir es el paso 1: Siempre cree nombres de archivo que estén garantizados como únicos. Olvídese de las esperas de 2 segundos y cosas así de las que habla la página del manual de Qmail.
Esa especificación requiere que la acción de la función sea atómica.