MAILDIR(5)

πŸ’Œ MAILDIR(5) β€” the E-mail directory glow-up πŸ’Œ

okay bestie, sit down, hydrate, because we're about to talk about maidirs... no wait, maildirs, and this one is not the dusty old mbox situation your ancestors were on. This page is from the MAILDIR(5) manual, written by S. Varshavchik, and it's giving main character energy for your whole mail spool. 🫢


✨ NAME ✨

maildir β€” E-mail directory. that's it, that's the vibe. a directory, but make it mail. πŸ’…


✨ SYNOPSIS ✨

$HOME/Maildir

literally just a path. iconic of her honestly.


✨ DESCRIPTION ✨

so a β€œMaildir” is a structured directory that holds E-mail messages. not just a pile of text, a whole structured situation. πŸ’–

maildirs were first implemented by the Qmail mail server. and Qmail's maildirs? they were a simple data structure, nothing more than a single collection of E-mail messages. cute, minimal, lowkey. but the Courier mail server builds upon Qmail's maildirs to provide extended functionality β€” folders, quotas, the whole deluxe package. πŸŽ€

this document describes the Courier mail server's extended maildirs, without explicitly calling out the Courier-specific extensions as such. for the original definition of maildirs, go see maildir(5) in Qmail's documentation. iykyk. πŸ“š

traditionally, E-mail folders were saved as plain text files called β€œmboxes”. and bestie, mboxes have known limitations, we have to talk about it 😭:

  • only one application can use an mbox at the same time.
  • locking is required to allow simultaneous concurrent access by different applications.
  • locking is often problematic, and not very reliable in network-based filesystem requirements. some network-based filesystems don't offer any reliable locking mechanism at all.
  • and even bulletproof locking won't prevent occasional mbox corruption. a process can be killed or terminated in the middle of updating an mbox. this will likely result in corruption, and a loss of most messages in the mbox. πŸ’€ not the message loss.

maildirs, on the other hand? maildirs allow multiple concurrent access by different applications. maildirs do not require locking. multiple applications can update a maildir at the same time, without stepping on each other's feet. periodt. 🌈


πŸ—‚οΈ Maildir contents πŸ—‚οΈ

a β€œmaildir” is a directory that's created by maildirmake(1)[1]. naturally, maildirs should not have any group or world permissions β€” unless, for some reason, you want other people to read your mail πŸ™ˆ (bestie. don't.).

a maildir contains three subdirectories: tmp, new, and cur. these three subdirectories comprise the primary folder, where new mail is delivered by the system. ✨

Folders are additional subdirectories in the maildir whose names begin with a period: such as .Drafts or .Sent. each folder itself contains the same three subdirectories, tmp, new, and cur, plus an additional zero-length file named maildirfolder. its whole purpose? to inform any mail delivery agent that it's really delivering to a folder, and that the mail delivery agent should look in the parent directory for any maildir-related information. she's a little note that says "hey, look up, not here". πŸŽ€

here's the tea: folders are not physically nested. a folder subdirectory like .Sent does not itself contain any subfolders. the main maildir contains a single, flat list of subfolders. but they're logically nested, and periods serve to separate folder hierarchies. for example, .Sent.2002 is considered to be a subfolder called β€œ2002” which is a subfolder of β€œSent”. flat on the outside, tree on the inside. queen behavior. πŸ‘‘

πŸ”€ Folder name encoding πŸ”€

folder names can contain any Unicode character, except for control characters. also US-ASCII characters U+0x0020 - U+0x007F, except for the period, and forward-slash. non-Latin characters are encoded in UTF-8. so go off, name your folders in any language, just mind the dots and slashes. πŸ’œ

πŸ“¦ Other maildir contents πŸ“¦

software that uses maildirs may also create additional files besides the tmp, new, and cur subdirectories β€” in the main maildir or a subfolder β€” for its own purposes. no gatekeeping, the maildir can hold a little extra. πŸ“


πŸ’Œ Messages πŸ’Œ

E-mail messages are stored in separate, individual files, one E-mail message per file. one message, one file, no sharing, no drama. πŸ’…

  • the tmp subdirectory temporarily stores E-mail messages that are in the process of being delivered to this maildir. tmp may also store other kinds of temporary files, as long as they are created in the same way that message files are created in tmp.
  • the new subdirectory stores messages that have been delivered to this maildir, but have not yet been seen by any mail application.
  • the cur subdirectory stores messages that have already been seen by mail applications.

so it's tmp β†’ new β†’ cur, a whole glow-up journey for every message. πŸ¦‹


πŸ“¬ Adding new mail to maildirs πŸ“¬

the following process delivers a new message to the maildir. get your notebook out, this is the protocol:

A new unique filename is created using one of two possible forms: time.MusecPpid.host, or time.MusecPpid_unique.host.

  • time and usec is the current system time, obtained from gettimeofday(2).
  • pid is the process number of the process that is delivering this message to the maildir.
  • host is the name of the machine where the mail is being delivered.

in the event that the same process creates multiple messages, a suffix unique to each message is appended to the process id; preferrably an underscore, followed by an increasing counter. this applies whether messages created by a process are all added to the same, or different, maildirs. ✨

this protocol allows multiple processes running on multiple machines on the same network to simultaneously create new messages without stomping on each other. collab, not chaos. 🀝

the filename created in the previous step is checked for existence by executing the stat(2) system call. if stat(2) results in ANYTHING OTHER than the system error ENOENT, the process must sleep for two seconds, then go back and create another unique filename. ⏰ yes, two whole seconds, it's an extra step to insure that each new message has a completely unique filename.

other applications that wish to use tmp for temporary storage should observe the same protocol β€” but peep READING MAIL FROM MAILDIRS below πŸ‘€, because old files in tmp will be eventually deleted.

if the stat(2) system call returned ENOENT, the process may proceed to create the file in the tmp subdirectory, and save the entire message in the new file. and now the important bits, no skimming:

the message saved MUST NOT have the β€œFrom_” header that is used to mboxes. the message also MUST NOT have any β€œFrom_” lines in the contents of the message prefixed by the β€œ>” character. 🚫

when saving the message, the number of bytes returned by the write(2) system call must be checked, in order to make sure that the complete message has been written out. no partial sends, we don't do that here. 😀

after the message is saved, the file descriptor is fstat(2)-ed. the file's device number, inode number, and its byte size are saved. the file is closed and is then immediately moved/renamed into the new subdirectory. the name of the file in new should be time.MusecPpidVdevIino.host,S=cnt, or time.MusecPpidVdevIino_unique.host,S=cnt. where:

  • dev is the message's device number,
  • ino is the message's inode number (from the previous fstat(2) call),
  • and cnt is the message's size, in bytes.

the ,S=cnt part optimizes the Courier[2] mail server's maildir quota enhancement; it allows the size of all the mail stored in the maildir to be added up without issuing the stat(2) system call for each individual message β€” and honestly, that can be quite a performance drain with certain network filesystems. she's efficient, she's thoughtful, she's ,S=cnt. πŸ”₯


πŸ“– READING MAIL FROM MAILDIRS πŸ“–

applications that read mail from maildirs should do it in the following order, bestie, in order:

  1. when opening a maildir or a maildir folder, read the tmp subdirectory and delete any files in there that are at least 36 hours old. πŸ•°οΈ yes, we clean as we go.
  2. look for new messages in the new subdirectory. rename new/filename, as cur/filename:2,info.

here, info represents the state of the message, and it consists of zero or more boolean flags chosen from the following:

  • β€œD” β€” this is a 'draft' message
  • β€œR” β€” this message has been replied to
  • β€œS” β€” this message has been viewed (seen)
  • β€œT” β€” this message has been marked to be deleted (trashed), but is not yet removed (messages are removed from maildirs simply by deleting their file)
  • β€œF” β€” this message has been marked by the user, for some purpose

these flags must be stored in alphabetical order. πŸ”€ note that new messages contain only the :2, suffix, with no flags, indicating that the messages were not seen, replied, marked, or deleted.

maildirs may have maximum size quotas defined, but these quotas are purely voluntary. 🀫 if you need to implement mandatory quotas, you should use any quota facilities provided by the underlying filesystem that is used to store the maildirs. the maildir quota enhancement is designed to be used in certain situations where filesystem-based quotas cannot be used for some reason.

the implementation is designed to avoid the use of any locking. as such, at certain times the calculated quota may be imprecise, and certain anomalous situations may result in the maildir actually going over the stated quota. πŸ’€ one such situation would be when applications create messages without updating the quota estimate for the maildir. eventually it will be precisely recalculated, but wherever possible new messages should be created in compliance with the voluntary quota protocol.

the voluntary quota protocol involves some additional procedures that must be followed when creating or deleting messages within a given maildir or its subfolders. the deliverquota(8)[3] command is a tiny application that delivers a single message to a maildir using the voluntary quota protocol, and hopefully it can be used as a measure of last resort. alternatively, applications can use the libmaildir.a library to handle all the low-level dirty details for them. the voluntary quota enhancement is described in the maildirquota(7)[4] man page. πŸŽ€


πŸ’° Maildir Quotas πŸ’°

this is a voluntary mechanism for enforcing "loose" quotas on the maximum sizes of maildirs. key word: voluntary. πŸ™ˆ

this mechanism is enforced in software, and not by the operating system. therefore it is only effective as long as the maildirs themselves are not directly accessible by their users β€” because this mechanism is trivially disabled. like, trivially trivially. πŸ’€

if possible, operating system-enforced quotas are preferrable. where operating system quota enforcement is not available, or not possible, this voluntary quota enforcement mechanism might be an acceptable compromise. ✨

since it's enforced in software, all software that modifies or accesses the maildirs is required to voluntarily obey and enforce a quota. the voluntary quota implementation is flexible enough to allow non quota-aware applications to also access the maildirs, without any drastic consequences. there will be some non-drastic consequences, though, and we're being honest about them:

  • of course, non quota-aware applications will not enforce any defined quotas.
  • furthermore, this voluntary maildir quota mechanism works by estimating the current size of the maildir, with periodic exact recalculation.
  • obviously, non quota-aware maildir applications will not update the maildir size estimation, so the estimate will be thrown off for some period of time, until the next recalculation.

so it's vibes-based bookkeeping with a scheduled reality check. lowkey genius, highkey fragile. πŸ¦‹


bestie we are not done yet β€” this page keeps going, part 2 is coming and there is more lore. stay seated. πŸ’–

Okay so bestie, it's time for the quota talk πŸ’… Buckle up, because this voluntary quota thing is not your average lock-it-all-down situation.

This voluntary quota mechanism is a whole vibe designed to be a reasonable compromise between actually working and not tanking performance. Like, the entire point of using maildir-based mail storage is to dodge locking completely and let a million apps read your mail in parallel, right? So to compute the exact size of a maildir, you'd have to lock it down to stop any changes while you add everything up. And obviously that defeats the whole original purpose of maildirs, so nope β€” the voluntary quota mechanism simply does not use locking. Which is exactly why the currently recorded maildir size is always considered an estimate. Regular size recalculations will clean up after any occasional race conditions that throw the estimate off. It's giving "trust the process, periodically recheck" ✨


🌸 Installing a quota ✨

You install a quota for an existing maildir by running maildirmake with the -q option and naming a maildir that already exists. The -q option takes a parameter, quota, which is a comma-separated list of quota specifications. A quota specification is a number followed by either:

  • S β€” the maximum message size in bytes 🧚
  • C β€” the maximum number of messages πŸ’Œ

For example:

maildirmake -q 5000000S,1000C ./Maildir

This sets the quota to 5,000,000 bytes or 1000 messages, whichever comes first. First one to hit the wall wins, no cap 🏁

maildirmake -q 1000000S ./Maildir

This sets the quota to 1,000,000 bytes, without limiting the number of messages. Size only, messages can run wild, periodt.


πŸ¦‹ Changing and deleting quotas 🌈

Wanna change the quota of an existing maildir? Just rerun the maildirmake command with a new -q option, literally that easy. And to delete a quota entirely β€” delete the Maildir/maildirsize file and it's gone. Poof. πŸ™ˆ


✨ SEE ALSO ✨


πŸ‘‘ AUTHOR πŸ‘‘

Sam Varshavchik

  • Author

The icon who wrote all this, we stan 🫢


πŸ“ NOTES πŸ“

  1. maildirmake(1) http://www.courier-mta.org/maildirmake.html
  2. Courier https://www.courier-mta.org
  3. deliverquota(8) http://www.courier-mta.org/deliverquota.html
  4. maildirquota(7) http://www.courier-mta.org/maildirquota.html

And that's the whole page, bestie! πŸŽ€ This lil' gem came out of the Courier Mail Server, dated 01/10/2026, and it lives under the name MAILDIR(5) in section 5. Go set those quotas and slay πŸ’…β­

πŸ“¦ where this page comes from
  • ubuntu stonking: maildrop 4.0.4-1 Β· GPL-3~with-OpenSSL-exception
  • πŸ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms