MAILDROP(1)

โœจ MAILDROP(1) โœจ

okay bestie, gather round, because today we're learning about maildrop โ€” it's a mail delivery filter/agent, and honestly? it's giving main character energy in your mail server's life. ๐Ÿ’Œ


๐ŸŒธ SYNOPSIS ๐ŸŒธ

maildrop [option...] [-d user] [arg...]

maildrop [option...] [filename] [arg...]

๐Ÿ’– DESCRIPTION ๐Ÿ’–

So like, maildrop is a replacement local mail delivery agent, and the way that it also comes with its own whole mail filtering language?? obsessed. You've got two ways your sysadmin can deploy it:

  • they swap out your existing mail delivery agent for maildrop, or
  • users just run maildrop through the old agent's 'forward to program' mechanism.

Either way, iconic. ๐Ÿ’…

First things first: maildrop reads the E-mail message off standard input. Trailing carriage return characters? automatically stripped, no cap. And a quick anatomy lesson for you: an E-mail message is header lines, then a blank line, then the contents of the message. periodt.

โš ๏ธ Now here's the tea, and listen closely: maildrop does not accept an mbox-style From_ line before the first header line. It also does not accept leading empty lines before the first non-blank header line. If your message could possibly start with empty lines and a From_ line, use reformail -f0 to strip any initial empty lines, and swap a From_ line for a proper Return-Path: header โ€” then pipe it to maildrop. Because otherwise it's just not gonna work, bestie. ๐Ÿ˜ญ

If the file /etc/maildroprc exists, the mail delivery or mail filtering instructions get read from that file. And those instructions can tell maildrop to save the message in a specific mailbox, discard it, return it to sender, or forward it to a different E-mail address. So many choices, so much power. ๐Ÿ‘‘

But if /etc/maildroprc doesn't exist, or its delivery instructions don't completely dispose of the message? Then maildrop moves on and reads the delivery instructions from $HOME/.mailfilter. And if that doesn't exist either, or its instructions still don't completely dispose of the message, maildrop just saves the E-mail in the default mailbox. Simple as that. โœจ

maildrop knows how to deliver mail to standard mailbox files, and it also knows how to deliver to maildirs. Quick vocab check: a maildir is a directory-based mail format used by the Courier[1] and Qmail mail servers, and loads of other mail servers know how to read maildirs too. And when it's delivering to mailbox files, maildrop will lock the mailbox for the duration of the delivery. Safety first, always. ๐Ÿ”’

That's the general mail delivery behavior. There are minor differences depending on maildrop's delivery mode, which gets determined by how maildrop was started. And there are three different primary operating modes:

๐ŸŒˆ Manual mode

A file containing filtering instructions โ€” filename โ€” is specified as an argument to the maildrop command. maildrop reads this filename and follows the instructions in it. And unless the message is explicitly forwarded, bounced, deleted, or delivered to a specific mailbox, it will be delivered to the user's system mailbox. ๐ŸŽ€

๐ŸŒˆ Delivery mode

Here maildrop is the mail server's mail delivery agent. maildrop runs in delivery mode when no filename is specified on the command line. It changes the current directory to the user's home directory, then reads /etc/maildroprc, then $HOME/.mailfilter. Order matters, bestie. ๐Ÿ“‚

๐ŸŒˆ Embedded mode

And now for the fancy one: maildrop functions as a part of another application. Embedded mode is used by the Courier[1] mail server to integrate mail filtering directly into the process of receiving mail from a remote mail relay โ€” which means it can reject unwanted mail before it is even accepted for local mail delivery. Rude to spammers, kind to you. ๐Ÿ’… Embedded mode is used when either the -m or the -M option is specified, and it's described below. (There's a more extensive description of embedded mode further down too โ€” see below, iykyk.)


๐Ÿ”’ SECURITY ๐Ÿ”’

Okay so, is it safe to install maildrop as a root setuid program? Yes. ๐Ÿ’š The Courier mail server[1] installs maildrop as a root setuid program by default, specifically so it can use maildrop in embedded mode. If root runs maildrop (or it's setuided to root), the -d option may be used to specify the message's recipient. And the moment that happens, maildrop immediately resets its userid to the one specified by the -d option. Then the user's $HOME/.mailfilter is read (if it exists), and the message is delivered to the indicated user. Clean. โœจ

Your system administrator can also configure maildrop to restrict the -d option for everyone except the mail system itself. Gatekeeping, but make it security. ๐Ÿ˜Œ

โš ๏ธ Now for the warnings, and these are real ones, so pay attention:
  • If, in delivery mode, the user's home directory has the sticky bit set, maildrop immediately terminates with an exit code of EX_TEMPFAIL, without doing anything. Mail servers interpret the EX_TEMPFAIL exit code as a request to reschedule the message for another delivery attempt later. Setting the sticky bit lets $HOME/.mailfilter be edited while temporarily holding all incoming mail. Cute trick, actually. ๐Ÿ“
  • maildrop also terminates with EX_TEMPFAIL if the user's home directory has world write permissions. Nope, absolutely not. ๐Ÿ’€
  • maildrop immediately terminates with EX_TEMPFAIL if the filename is not owned by the user, or if it has any group or world permissions โ€” and yes, that includes read permissions. The permissions on $HOME/.mailfilter may only include read and write privileges to the user. Nothing else. ๐Ÿ™ˆ
  • When using the special embedded mode (see below), maildrop immediately terminates with the exit code set to EX_TEMPFAIL if $HOME/.mailfilters is not owned by the user, or if it has any group or world permissions. Same energy, different file. ๐Ÿšซ

๐Ÿงš TEMPORARY FILES ๐Ÿงš

maildrop is heavily optimized and tries to use as little resources as possible, because it's an efficient queen. ๐Ÿ’…

  • Small messages? maildrop reads them straight into memory, then filters and/or delivers the message directly from memory. ๐Ÿง โœจ
  • Larger messages? maildrop accesses the message directly from the file.
  • Standard input not a file? Then maildrop writes the message to a temporary file, and accesses the message from that temporary file instead. That temporary file is automatically removed when the message is delivered. Cleanup slay. ๐ŸŽ€

โœจ OPTIONS โœจ

okay bestie, here's the whole menu of flags, and yes, we're going through every single one ๐Ÿ’…

  • -a โ€” makes using the Courier Authentication Library mandatory, like fr fr required. If the call to the authlib mechanism fails for literally any reason โ€” say authdaemon is inaccessible โ€” maildrop throws a temporary error code. ๐Ÿ™ˆ
Note: this might already be the default depending on how maildrop was configured on your system. So check before you @ me.
  • -A "Header: value" โ€” adds an extra header to the message. Writing -A "Foo: Bar" effectively adds that header to the message being delivered. โœจ

So here's the tea: the mail transport agent usually adds extra headers when it delivers a message to a local mailbox. The usual way this goes down is the MTA pipes the message to the local delivery agent โ€” like maildrop โ€” and tacks on some extra headers in the process. And because maildrop gets the message through a pipe, it has to either hold the whole message in memory or write it out to a temporary file. ๐Ÿ˜ญ

The -A option lets the file containing the message be handed to maildrop directly as standard input instead, with the extra headers specified on the command line. And because standard input is a file, maildrop doesn't need a temporary file at all. Iconic. Multiple -A options may be specified. ๐Ÿ‘‘

  • -d user โ€” runs maildrop in delivery mode for this user ID.

Your system administrator may optionally restrict the -d option so only the mail system can use it, meaning it might not be available to you. But in all cases, -d is allowed if user is the same user who's running maildrop. Also, for -d to work at all, maildrop must be executed by root, or maildrop must be a root-owned program with the setuid bit set. And if there's no filename on maildrop's command line, that implies the -d option for the user running maildrop.

If -d is not specified, the first argument following all the options is the name of the file containing filtering instructions. Any remaining arguments get assigned to the variables $1, $2, and so on (see "Environment" and "Variable substitution").

  • -f address โ€” sets the FROM variable (the message envelope sender) to address. Your system administrator may optionally disable the -f option for users, so ngl this one might not be available to you either. ๐Ÿซถ
  • -m โ€” runs maildrop in embedded mode. You can use both -m and -d together, but it really doesn't make much sense. Even if you genuinely wanted to run your message through somebody else's .mailfilter, that .mailfilter probably has at least one instruction that isn't allowed in embedded mode. ๐Ÿ’€

The filename argument to maildrop should be specified. filename is a file that includes filtering instructions to be processed in embedded mode. The -m option is used for debugging filter files that later get placed in $HOME/.mailfilters and used with the -M option.

  • -M filterfile โ€” runs maildrop in a special embedded mode. The -d option is implied when -M is used, and if it's absent it defaults to the userid running maildrop.

All the requirements for the -d option apply. maildrop must either be executed by root, or the maildrop program must be owned by root with the setuid bit set. maildrop immediately gives up root privileges by changing its user ID to the one specified by -d, then reads $HOME/.mailfilters/filterfile. For security reasons the name of the file may not begin with a slash or include periods. And maildrop is very paranoid: both $HOME/.mailfilters and $HOME/.mailfilters/filterfile must be owned by the user, and may not have any group or world permissions. ๐Ÿšจ

The -M option allows for some friendly cooperation between the user running the application and the user who provides a filter for the embedded mode. The user running the application can use someone else's canned filter and be assured that the filter is not going to run amok and start sending mail or create files all over the place. And the user who provides the filter can be assured that the environment variables are clean and that there are no surprises. mutual trust, we love to see it ๐Ÿซถ

maildrop also supports the concept of "default" filter files. If the file specified by the -M option can't be found in $HOME/.mailfilters, maildrop will try to open $HOME/.mailfilters/filterfileprefix-default. Here filterfileprefix is the initial part of filterfile up until the last - character in filterfile.

If $HOME/.mailfilters/filterfileprefix-default doesn't exist, and there are any other dashes left in filterfileprefix, maildrop removes the last dash and everything following it, then tries again.

And as a last resort, maildrop tries to open $HOME/.mailfilters/default. ๐ŸŽ€

For example, if the parameter to the -M option is mailfilter-lists-maildrop, maildrop will try to open the following files, in order:

Note: maildrop looks for -default files ONLY if -M is used. iykyk ๐Ÿ’…
  • -D uuu/ggg โ€” this option is reserved for use by the version of maildrop that comes integrated with the Courier mail server. Not for us, bestie, it's for the Courier girlies. ๐Ÿ™ˆ
  • -V level โ€” initializes the VERBOSE variable to level. Because maildrop parses the entire file before running it, this option is what produces debugging output during the parsing phase. Otherwise, if filename has syntax errors, no debugging output is possible at all, because the VERBOSE variable isn't set yet. ๐Ÿ˜ญ

Pro tip: -V is ignored when maildrop runs in delivery mode.

  • -w N โ€” the -w N option places a warning message into the maildir if the maildir has a quota setting, and after the message was successfully delivered the maildir was at least N percent full. heads up vibes ๐ŸŒธ
  • -W filename โ€” copies the warning message from filename, or from /etc/quotawarnmsg if this option isn't specified, with the addition of the "Date:" and "Message-Id:" headers. The warning gets repeated every 24 hours (at least), until the maildir drops below N percent full. โฐ
  • -t socket โ€” this option is available if maildrop is compiled with optional Dovecot authentication support. socket specifies the location of the Dovecot master authentication socket, for example /var/run/dovecot/auth-master.

๐Ÿ’Œ DELIVERY MODE ๐Ÿ’Œ

If a filename isn't specified on the command line, or if the -d option is used, maildrop runs in delivery mode. In delivery mode, maildrop changes to the home directory of the user specified by the -d option (or the user who's running maildrop if -d wasn't given) and reads $HOME/.mailfilter for filtering instructions. $HOME/.mailfilter must be owned by the user and have no group or global permissions โ€” and bestie, maildrop terminates if it does. no cap. ๐Ÿ’€

If $HOME/.mailfilter doesn't exist, maildrop will simply deliver the message to the user's mailbox. easy peasy โœจ

And if the file /etc/maildroprc exists, maildrop reads filtering instructions from that file first, before reading $HOME/.mailfilter. This is how the system administrator provides global filtering instructions for all users. ๐ŸŒˆ

Note: /etc/maildroprc is read only in delivery mode.

๐Ÿ‘ฅ VIRTUAL ACCOUNTS ๐Ÿ‘ฅ

The -d option can also specify a name of a virtual account or mailbox. Check the makeuserdb(1) manual page in the Courier Authentication library's documentation for more info. ๐Ÿ“–


๐Ÿงš EMBEDDED MODE ๐Ÿงš

Embedded mode is what you use when you want maildrop's filtering abilities but no actual mail delivery is needed. In embedded mode, maildrop is executed by another application and is passed the -m or the -M option. maildrop reads the message, then runs the filtering rules specified in filename.

filename may contain any filtering instructions EXCEPT the following, bestie โ€” these are the forbidden ones:

  • ` ... ` โ€” text strings delimited by back-tick characters (run shell command) are not allowed.
  • cc โ€” the cc command is not allowed in embedded mode.
  • dotlock โ€” the dotlock command is not allowed in embedded mode.
  • flock โ€” the flock command is not allowed in embedded mode.
  • gdbmopen โ€” in embedded mode, GDBM databases may be opened only for reading.
  • log โ€” the log command is not allowed in embedded mode.
  • logfile โ€” the logfile command is not allowed in embedded mode.
  • system โ€” the system command is not allowed in embedded mode.
  • to โ€” the to command is not allowed in embedded mode.
  • xfilter โ€” the xfilter command is not allowed in embedded mode.

Normally, when filename doesn't explicitly deliver a message, maildrop will deliver the message to the user's default mailbox. That's also disabled in embedded mode. ๐Ÿ™…โ™€๏ธ

The filename may communicate with the parent application by using the echo statement and the EXITCODE environment variable. cute lil handshake ๐Ÿซถ

๐ŸŒธ /etc/maildroprcs ๐ŸŒธ

If maildrop encounters an include statement where the filename starts with /etc/maildroprcs/, the normal restrictions for embedded mode are suspended while executing the filter file in the /etc/maildroprcs directory. The restrictions are also suspended for any additional filter files that are included from /etc/maildroprcs. Then the restrictions resume once maildrop finishes executing the file from /etc/maildroprcs. ๐ŸŽ€

This lets the system administrator have a controlled environment for running external commands (via the backticks, the system or the xfilter commands).

The name of the file may not contain any periods โ€” this is so a creative individual can't write include "/etc/maildroprcs/../../home/user/recipe". ๐Ÿ’… nice try though

Before executing the commands in the /etc/maildroprcs file, maildrop automatically resets the following variables to their initial values: DEFAULT, HOME, LOCKEXT, LOCKSLEEP, LOCKTIMEOUT, LOCKREFRESH, LOGNAME, PATH, SENDMAIL, and SHELL. And please note: the previous values of these variables (if they were changed) will NOT be restored once maildrop finishes executing the commands from /etc/maildroprcs. ๐Ÿšจ


โฑ๏ธ WATCHDOG TIMER โฑ๏ธ

maildrop has a watchdog timer that attempts to abort runaway filtering. If filtering isn't complete within a predefined time interval (defined by the system administrator, usually five minutes), maildrop terminates. so dramatic. love that for it. ๐Ÿ•


๐Ÿ“ FILES ๐Ÿ“

  • /etc/passwd โ€” sets the user's home directory and related variables. If NIS/YP is installed, that will be used as well.
  • /etc/maildroprc โ€” global filtering instructions for delivery mode.
  • /var/mail โ€” system mailbox (the actual directory is defined by the system administrator).
  • /usr/sbin/sendmail โ€” program to forward mail (the exact program is defined by the system administrator).
  • $HOME/.mailfilter โ€” filtering instructions in delivery mode.
  • $HOME/.mailfilters โ€” directory containing files used in special embedded mode.

โœจ SEE ALSO โœจ

okay bestie, here's the whole friend group, no cap ๐Ÿ’– โ€” go read these when you're done slaying with this page:


๐Ÿ‘‘ AUTHOR ๐Ÿ‘‘

  • Sam Varshavchik โ€” Author

like, actual legend behavior fr fr ๐Ÿซถ


๐ŸŒธ NOTES ๐ŸŒธ

the footnotes!! everything below is the exact tea, one numbered receipt at a time โœจ

  1. Courier โ€” https://www.courier-mta.org
  2. "Environment" โ€” http://www.courier-mta.org/maildrop/maildropfilter.html#environment
  3. "Variable substitution" โ€” http://www.courier-mta.org/maildrop/maildropfilter.html#varsubst
  4. is passed the โ€m or the โ€M option. โ€” http://www.courier-mta.org/maildrop/#options
  5. cc โ€” http://www.courier-mta.org/maildrop/maildropfilter.html#cc
  6. dotlock โ€” http://www.courier-mta.org/maildrop/maildropfilter.html#dotlock
  7. flock โ€” http://www.courier-mta.org/maildrop/maildropfilter.html#flock
  8. gdbmopen โ€” http://www.courier-mta.org/maildrop/maildropgdbm.html
  9. log โ€” http://www.courier-mta.org/maildrop/maildropfilter.html#log
  10. system โ€” http://www.courier-mta.org/maildrop/maildropfilter.html#system
  11. to โ€” http://www.courier-mta.org/maildrop/maildropfilter.html#to
  12. xfilter โ€” http://www.courier-mta.org/maildrop/maildropfilter.html#xfilter
  13. echo โ€” http://www.courier-mta.org/maildrop/maildropfilter.html#echo
  14. include โ€” http://www.courier-mta.org/maildrop/maildropfilter.html#include
  15. lockmail(1) โ€” http://www.courier-mta.org/maildrop/lockmail.html
  16. maildropfilter(7) โ€” http://www.courier-mta.org/maildrop/maildropfilter.html
  17. makedat(1) โ€” http://www.courier-mta.org/maildrop/makedat.html
  18. maildropex(7) โ€” http://www.courier-mta.org/maildrop/maildropex.html
  19. reformail(1) โ€” http://www.courier-mta.org/maildrop/reformail.html
  20. makemime(1) โ€” http://www.courier-mta.org/maildrop/makemime.html
  21. reformime(1) โ€” http://www.courier-mta.org/maildrop/reformime.html
  22. courier(8) โ€” http://www.courier-mta.org/maildrop/courier.html

and that's the whole page bestie, you read all three parts, that's main character energy ๐Ÿ’… go filter some mail, you absolute icon ๐Ÿ˜ญ๐Ÿ’–

this lil manual is brought to you by Courier Mail Server, dated 01/10/2026, and it's the MAILDROP(1) page โ€” periodt โœจ๐ŸŽ€๐Ÿฆ‹

๐Ÿ“ฆ 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