COURIERFILTER(8)
π COURIERFILTER(8) β the courierfilter manual, bestie edition π
okay so. this is the page for courierfilter(8), part of the Courier Mail Server, and it was written by S. Varshavchik. it's about Courier mail filters β the little guardians that vibe-check your mail before it gets in. let's get into it, no cap. π¦
β¨ SYNOPSIS β¨
courierfilter [[start] | [stop] | [restart]]
filterctl [[start] | [stop]] [filter]
that's it. that's the whole vibe. π
πΈ DESCRIPTION πΈ
so the filterctl commands are the ones that install or uninstall your global mail filters. global mail filters are the ones that selectively block unwanted mail, like little bouncers for your inbox. and the slay thing? you can have more than one mail filter enabled at the same time. more bouncers, more protection, periodt.
three filters β dupfilter(8), verifyfilter(8) and courierperlfilter(8) β are literally shipped as examples so you can see how to write your own mail filters. free templates, bestie!! π
courierfilter start runs all the mail filters that have been installed by filterctl. courierfilter stop shuts down all running mail filters. and here's the tea:
- after
courierfilter start, anyfilterctlcommands take effect immediately β‘ - after
courierfilter stop, anyfilterctlcommands will take effect at the nextcourierfilter start
courierfilter restart signals the running courierfilter to reread its configuration files. this is normally done automatically, by filterctl. so you don't even have to think about it most of the time. iconic behaviour honestly. π
okay now the serious part, and it's giving main character energy because it's the whole reason this exists:
if any mail filter is installed, the mail filter must be running in order for any mail to be processed. mail filters are assumed to be empowered to enforce system-wide mail policies, so if an installed mail filter is not running then mail will not be accepted by the system. π
and listen β it won't reject the mail, if possible. every attempt will be made to send a temporary error code to an external mail system, asking it to try again later. so it's a "not rn, come back later" not a "we're done here."
for this reason (this is the important admin homework, bestie), you should modify your system boot script to run courierfilter start as soon as possible, and run courierfilter stop during the final portion of your system shutdown script. π«Ά
and good news: it is not necessary to run courierfilter if you do not install a mail filter with filterctl. so if you're not using any filters, you can just. not. zero drama. β¨
π§ MAIL FILTER IMPLEMENTATION π§
this section explains how mail filters are implemented, and how to write a new global mail filter. grab a snack, we're going in. π
available mail filter binaries live in the directory /usr/lib/courier/filters. the filterctl script looks in this directory to see which mail filters are available to be installed. and installing a mail filter is so simple it's lowkey funny: you just create a soft link from the directory /etc/courier/filters/active to its corresponding binary in /usr/lib/courier/filters. that's the whole install. no cap. π
the courierfilter start command simply reads /etc/courier/filters/active and runs every program in this directory.
the filterctl script sends a HUP signal to courierfilter after installing or uninstalling a filter. courierfilter will reread the contents of /etc/courier/filters/active then start or stop individual mail filters. automatic. effortless. we love to see it. π
the socket part (listen up) π
after starting, an individual mail filter must create a filesystem domain socket in one of two directories:
/var/lib/courier/filters/var/lib/courier/allfilters
the name of the socket should be the same as a name of the filter, and the mail filter must make sure to remove any socket by the same name in the other directory.
for various silly reasons, the recommended implementation is to create /var/lib/courier/filters/.NAME or /var/lib/courier/allfilters/.NAME (after making sure that it doesn't exist) then rename .NAME to NAME. sneaky little rename, honestly genius. π§ β¨
file descriptor 3, the moment everyone fears π€
after initializing the socket, the mail filter must then close its file descriptor #3. file descriptor 3 is inherited by every mail filter that's executed by the courierfilter start command.
the mail filter's file descriptor 3 is connected to the write end of a pipe, which may be relevant to certain ways of implementing the closing of the file descriptor β for instance in Perl where you may be forced to pseudo-open the descriptor (in write mode) before closing it. (perl girlies, you know the struggle. π)
the courierfilter start command will not exit until every started mail filter closes its file descriptor 3. this allows for all mail filters to orderly initialize themselves before the courierfilter start command returns. so it waits for you. patiently. like a good friend. π«Ά
stdin and the two jobs π₯
all mail filters also inherit a pipe on standard input, and must terminate when the pipe is closed. mail filters must simultaneously:
- listen for new connections on the mail filter socket
- watch for their standard input to close
two things at once. multitasking queen. π
what actually arrives on the socket π
the mail filter receives a new connection on its socket for every message that needs to be filtered. after establishing a connection, the mail filter will immediately read the following information from the new socket:
- a pathname to a file containing the contents of the message
- one or more pathnames to control files for this message
each pathname is terminated by a single newline character. the last pathname is followed by a second newline character. the pathnames may either be relative pathnames to /usr or absolute pathnames, depending on the system configuration.
the verdict π
the mail filter is free to judge the message's worthiness by reading its contents and/or control file(s) as soon as a second consecutive newline character is received. (vibe check complete.)
the final verdict is rendered by writing back a result code on the same socket. and here's the detail that matters: the result code follows the same format as regular SMTP replies (even though the message may not have been received via SMTP), and can be used to communicate:
- acceptance β
- temporary failure β³
- a permanent failure π
if it's a failure, then the text portion of the result code will be used, if possible. the result code may be a multiline response, just like a regular SMTP reply. and then β immediately β the mail filter must close the connection after writing the result code. after closing the socket the mail filter must then proceed to wait for another connection request on the original listening socket. no lingering. no loitering. β¨
threads, tasks, and the graceful exit π¦
the mail filter can be multithreaded or multitasked, and can accept multiple connections simultaneously. when its standard input is closed the mail filter should stop accepting new connections and wait for any existing connections to be closed, prior to exiting. graceful. elegant. we stan a clean shutdown. π
the big scary warning β οΈ
global mail filters must be EXTREMELY resilient to runtime failures. since mail will not be processed if an installed mail filter is not running, if a mail filter crashes it will effectively shut down the mail server. currently courierfilter does not attempt to restart mail filters which crash.
EXTREMELY. that's the word they used. capital letters and everything. so like. write good code bestie. ππ₯
π MAIL FILTER INVOCATION π
the system administrator defines what mail gets filtered by editing the contents of the enablefiltering configuration file in /etc/courier. this configuration file contains a list of mail sources that should be filtered, like esmtp or local. see courier(8) for more information. a default /etc/courier/enablefiltering file is installed that specifies only the esmtp mail source as subject to filtering.
a message is not subject to filtering if its source is not listed in /etc/courier/enablefiltering. otherwise the following rules apply. π
certain mail destinations have the ability to selectively whitelist arbitrary messages. for example, local mail recipients have the ability to selectively whitelist individual messages, provided that a local mail filter (independent of any global mail filter) is installed that implements the maildrop filtering API. π
new messages are filtered by connecting to every socket in /var/lib/courier/filters and/or /var/lib/courier/allfilters, one at a time. all mail filters must accept the message, for it to be accepted by Courier. and if a socket exists but a connection cannot be established then the message is not accepted, and a temporary failure indication is returned. that's why no mail will be accepted unless all installed mail filters are running. yeah. all of them. the whole group chat has to agree. π
mail recipients that did not whitelist the sender, via the maildrop API, will have their mail filtered against everything in /var/lib/courier/filters and /var/lib/courier/allfilters. mail to recipients that whitelisted the sender, or mail to destinations that do not use a maildrop API-compatible filter, will be filtered only against the contents of /var/lib/courier/allfilters.
this gives system administrators a choice whether to install selective, or mandatory mail filters, or a combination of both. options!! we love options!! πΈ
π BUGS π
- many filesystem domain socket implementation are buggy. (yes bestie, that's how it's written. it's giving legacy code.)
- handling of crashed mail filters could be improved. π«
π FILES π
/usr/lib/courier/filtersβ available mail filters./etc/courier/filtersβ miscellaneous configuration files./etc/courier/filters/activeβ installed mail filters./etc/courier/enablefilteringβ which mail sources to filter./var/lib/courier/allfiltersβ mandatory filters./var/lib/courier/filtersβ optional filters.
π SEE ALSO π
localmailfilter(7), courier(8), dupfilter(8), ratefilter(8), verifyfilter(8), courierperlfilter(8).
π AUTHOR π
Sam Varshavchik β Author.
π NOTES π
dupfilter(8)β https://www.courier-mta.org/dupfilter.htmlverifyfilter(8)β https://www.courier-mta.org/verifyfilter.htmlcourierperlfilter(8)β https://www.courier-mta.org/courierperlfilter.htmlcourier(8)β https://www.courier-mta.org/courier.html- maildrop filtering API β https://www.courier-mta.org/localmailfilter.html
ratefilter(8)β https://www.courier-mta.org/ratefilter.html
okay that's the whole page bestie!! π this one came from Courier Mail Server, dated 01/10/2026, and it's page COURIERFILTER(8) in section 8 of the manual. go forth and filter responsibly, and remember: if your filter crashes, everything crashes. no pressure. β¨π¦π
π¦ where this page comes from
- ubuntu stonking: courier-mta 2.0.6-1 Β· GPL-3+~with-OpenSSL-exception
- Copyright 1998 - 2007 S. Varshavchik. See COPYING for -->
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms