{
    "mode": "man",
    "parameter": "maildropfilter",
    "section": "7",
    "url": "https://www.chedong.com/phpMan.php/man/maildropfilter/7/json",
    "generated": "2026-05-30T05:14:47Z",
    "synopsis": "/etc/maildroprc, $HOME/.mailfilter, $HOME/.mailfilters/*, and friends...",
    "sections": {
        "NAME": {
            "content": "maildropfilter - maildrop's filtering language\n",
            "subsections": []
        },
        "SYNOPSIS": {
            "content": "/etc/maildroprc, $HOME/.mailfilter, $HOME/.mailfilters/*, and friends...\n",
            "subsections": []
        },
        "DESCRIPTION": {
            "content": "This manual page describes the language used by maildrop to filter E-mail messages. The mail\nfiltering instructions are read from a file. The language is loosely structured, it is based\non pattern matching. The language has a distinct lexical and syntactical structure, very\nsimilar to Perl's, but it is important to note that it is not Perl, and is very different\nfrom Perl, in certain cases.\n\nIf the filtering instructions do not exist, maildrop delivers the message to the default\nmailbox without doing any additional processing, making it indistinguishable from the usual\nmail delivery agent.\n\nIt is important to note that maildrop reads and parses the filter file before doing anything.\nIf there are any errors maildrop prints an error message, and terminates with the exit code\nset to EXTEMPFAIL. A compliant mail transport agent should re-queue the message for a later\ndelivery attempt. Hopefully, most simple syntax errors will not cause mail to be bounced back\nif the error is caught and fixed quickly.\n",
            "subsections": [
                {
                    "name": "Environment",
                    "content": "maildrop uses variables to access and manipulate messages. Variables are arbitrary text\naccessed by referring to the name of the variable, such as HOME, or DEFAULT. Text is placed\ninto a variable by using an assignment statement, such as:\n\nFILE=\"IN.junk\"\n\n\nThis statement puts the text \"IN.junk\" (without the quotes) into a variable whose name is\nFILE. Later, the contents of a variable are accessed by using the $ symbol and the name for\nthe variable. For example:\n\nto $FILE\n\n\nThis will deliver the current message to the mailbox file (or a maildir directory) named\n\"IN.junk\".\n\nmaildrop initially creates variables from the environment variables of the operating system,\nUNLESS maildrop runs in delivery mode. Each operating system environment variable becomes a\nmaildrop variable. When running in delivery mode, maildrop does not import the environment\nfor security reasons, except for the environment variables that define the process locale\n(LANG, LANGUAGE, and LC*), which are still imported.\n\nIn all cases maildrop resets the following variables to their default values: HOME, DEFAULT,\nSHELL, PATH, LOCKEXT, LOCKREFRESH, LOCKSLEEP, LOCKTIMEOUT, MAILDIRQUOTA, SENDMAIL and\nLOGNAME.\n\nThere's one exception to this rule which applies to the version of maildrop that comes with\nthe Courier mail server[1]. The following does not apply to the standalone version of\nmaildrop: when running in delivery mode, if the -d flag was not used, or if it specifies the\nsame userid as the one that's running maildrop: the following variables are automatically\nimported from the environment: HOME, SHELL, LOGNAME and MAILDIRQUOTA. These environment\nvariables are initialized by the Courier mail server prior to running maildrop. Additionally,\nthe initial value for the DEFAULT maildrop variable is imported from the MAILDROPDEFAULT\nenvironment variable. This is because the Courier mail server overloads the DEFAULT\nenvironment variable to store the defaulted portion of the local mailbox address. See the\ndot-courier(5)[2] man page in the Courier mail server distribution. You can get the Courier\nmail server's DEFAULT value by using the import command. Note, however, that this will\nclobber the old contents of DEFAULT, which is probably not what you want. The right way to do\nthis would be something like this:\n\nSAVEDEFAULT=$DEFAULT\nimport DEFAULT\nLOCALDEFAULT=$DEFAULT\nDEFAULT=$SAVEDEFAULT\n\n\nAll internal variables are exported back as environment variables when maildrop runs an\nexternal command. Changes to internal variables, made by the filter file, are reflected in\nthe exported environment.\n"
                },
                {
                    "name": "Lexical structure",
                    "content": "Most whitespace is generally ignored. The # character introduces a comment running to the end\nof the line, which is also ignored. Unlike other mail filters, maildrop parses the filter\nfile before taking any action with the message. If there are syntax errors in the file,\nmaildrop displays an error message, and returns EXTEMPFAIL. That should cause the mail\nmessage to remain in the queue, and, hopefully allow the problem to be corrected, without\nbouncing any mail.\n\nNote\nIn maildrop, the end of line is a lexical token. In order to continue a long statement on\nthe next line, terminate the line with a backslash character.\n"
                },
                {
                    "name": "Literal text",
                    "content": "Literal text in the maildrop filtering language is surrounded by either single or double\nquotes. In order to enter a single quote into a text literal surrounded by single quotes, or\na double quote into a literal surrounded by double quotes, prefix it with a backslash\ncharacter. Use two backslash characters characters to enter one backslash character in the\ntext literal.\n\nNote\nA backslash followed by either a backslash, or a matching quote, is the only situation\nwhere the backslash character is actually removed, leaving only the following character\nin the actual text literal. If a backslash character is followed by any other character,\nthe backslash is NOT removed.\n\nMultiple text literals in a row are automatically concatenated, even if they use different\nquotes. For example:\n\nFOOBAR=\"Foo\"'bar'\nSAVEDEFAULT=$DEFAULT\nimport DEFAULT\nLOCALDEFAULT=$DEFAULT\nDEFAULT=$SAVEDEFAULT\n\n\nThis sets the variable FOOBAR to the text \"Foobar\".\n"
                },
                {
                    "name": "Variable substitution",
                    "content": "Variable substitution is performed on text literals that's surrounded by double quotation\nmarks. The \"$\" character, followed by a variable name, is replaced by that variable's\ncontents.\n\nMAILBOX=\"$HOME/Mailbox\"\n\n\nThis sets the variable MAILBOX to the contents of the variable HOME followed by \"/Mailbox\".\nVariable names must begin with an uppercase letter, a lowercase letter, or an underscore.\nFollowing that, all letters, digits, and underscores are taken as a variable name, and its\ncontents replace the $ sign, and the variable name. It is possible to access variables whose\nname includes other characters, by using braces as follows:\n\nMAILBOX=\"${HOME-WORD}/Mailbox\"\n\n\nInserts the contents of the HOME-WORD variable. If the variable does not exist, the empty\ntext literal is used to replace the variable name. It is not possible to access variables\nwhose names include the } character.\n\nIf the $ character is not followed by a left brace, letter, or an underscore, the $ character\nremains unmolested in the text literal. A backslash followed by the $ character results in a\n$ character in the text literal, without doing any variable substitution.\n\nVariable substitution is not done in text literals which are surrounded by single quotes\n(apostrophes).\n"
                },
                {
                    "name": "Command line arguments",
                    "content": "maildrop initializes special variables: $1, $2, and so on, with additional parameters\nspecified on the maildrop command line. A filter file may use those variables just like any\nother variables.\n"
                },
                {
                    "name": "Predefined variables",
                    "content": "The following variables are automatically defined by maildrop. The default values for the\nfollowing variables may be changed by the system administrator. For security reasons, the\nvalues of the following variables are always reset to their default values, and are never\nimported from the environment:\n\nDEFAULT\nThe default mailbox to deliver the message to. If the filter file does not indicate a\nmailbox to deliver this message to, the message is delivered to this mailbox. The default\nmailbox is defined by the system administrator.\n\nFROM\nMessage envelope sender. This is usually the same address as what appears in the From:\nheader, but may not be. This information may or may not be available to maildrop on your\nsystem. The message envelope sender is usually specified with the -f option to maildrop.\nIf the -f option is not given, maildrop looks for the Return-Path: header in the message.\nAs the last resort, FROM defaults to “MAILER-DAEMON”. Note that FROM may be empty - the\nmessage envelope sender is empty for bounce messages.\n\nHOME\nHome directory of the user running maildrop.\n\nHOSTNAME\nNetwork name of the machine running maildrop. Obtained from gethostname(3).\n\nLOCKEXT\nExtension for dot-lock files (default: .lock).\n\nLOCKREFRESH\nRefresh interval, in seconds, for dot-locks (default: 15). When maildrop dot-locks a\nmailbox, maildrop tries to refresh the lock periodically in order to keep other programs\nfrom removing a stale dot-lock. This is only required if a dot-lock exists for a\nprolonged period of time, which should be discouraged anyway.\n\nLOCKSLEEP\nNumber of seconds to wait to try again to create a dot-lock file, if one already exists\n(default: 5).\n\nLOCKTIMEOUT\nNumber of seconds to wait before removing a stale dot-lock file (default: 60). If a\ndot-lock file still exists after LOCKTIMEOUT seconds, maildrop assumes that the process\nholding the lock no longer exists, and the dot-lock file can be safely removed. After\nremoving the dot-lock file, maildrop waits LOCKSLEEP seconds before trying to create its\nown dot-lock file, in order to avoid a race condition with another process which is also\ntrying to remove the same stale dot-lock, at the same time.\n\nLOGNAME\nName of the user to who the message is being delivered.\n\nMAILDROPOLDREGEXP\nRevert to using the old legacy pattern matching engine. Versions of maildrop prior to\nversion 2.0 (included in the Courier mail server 0.51, and earlier), used a built-in\npattern matching engine, instead of using the PCRE library (see the “Patterns” section).\nmaildrop 1.x used a different syntax for patterns, which is no longer described in this\nmanual page. The old pattern matching engine is still available, by setting\nMAILDROPOLDREGEXP to “1”. Setting this variable will use the legacy pattern matching\nengine for the rest of the maildrop recipe file.\n\nThe pattern matching engine will be removed completely in a future version of maildrop.\nThis setting provides for a transitional period of converting old recipes.\nMAILDROPOLDREGEXP can be set to “1” in the global maildroprc file, then reset to “0” in\neach individual maildrop recipe file, after it gets converted to the new syntax.\n\nMAILFILTER\nThis is the name of the original filter file that was given to maildrop on the command\nline. This is mostly useful to -default filter files, it allows them to obtain the value\nof the -M option[3] specified on the command line.\n\nPATH\nCommand execution path.  maildrop resets PATH to the system default (usually\n/bin:/usr/bin:/usr/local/bin).\n\nSENDMAIL\nThe mail delivery agent. When maildrop is instructed to deliver the message to a mailbox\nwhose name begins with the ! character, this is interpreted as a request to forward the\nmessage. The SENDMAIL command is executed to forward the message.\n\nSHELL\nThe login shell. The shell is used to execute all commands invoked by maildrop.\n\nVERBOSE\nCurrent Debug level (default: 0). Setting VERBOSE to progressive higher values, between 1\nand 9, produces debugging output on standard error.  maildrop ignores the VERBOSE\nvariable in delivery mode (in order not to confuse the mail transport agent).\n\nUMASK\nThe file creation mode mask, in octal. The default setting of 077 creates mailboxes that\nare readable and writable by the owner only. Use 007 to create mailboxes that are\nreadable/writable by both owner and the group. Use 037 to create mailboxes that are\nreadable by both owner and group, but writable by owner only. Permissions on existing\nmailboxes are not changed, this setting affects only new mailboxes. When delivering to\nmaildirs this setting sets the permissions on new messages only. Access permissions on\nmessages in maildirs are also affected by the permissions on the maildir directories.\n"
                },
                {
                    "name": "Other special variables",
                    "content": "The following variables are automatically used by maildrop when the filter file is being\nprocessed:\n\nEXITCODE\nReturn code for maildrop. When maildrop successfully delivers a message, it terminates\nwith this exit code, which defaults to 0. When the to or the cc command is used to\ndeliver the message to an external process, via a pipe, maildrop will set this variable\nto the exit code of the external process. Since maildrop immediately terminates after\ncompleting the to command this means that maildrop's exit code will be the exit code of\nthe external process. If the to command does not deliver the message to a process you\nmust set EXITCODE before the to command, since maildrop terminates immediately after\nfinishing the delivery.\n\nFLAGS\nThe FLAGS variable is used only when delivering a message to a maildir, and may contain\nonly the following letters: “D”, “F”, “R”, and “S”. They may appear in any order. When\nthe message gets delivered to the maildir, the message will be marked with a draft, flag,\nreplied, or seen, attribute, correspondingly.\n\nFLAGS must be set before the message is delivered to a maildir. The contents of FLAGS are\nignored, when delivering on an mbox folder.\n\nKEYWORDS\nThe KEYWORDS variable is used only when delivering a message to a maildir, and implements\nthe optional IMAP keyword extension as implemented in the Courier IMAP server[1]. It may\nbe optionally initialized to contain a comma-separate list of keywords. The to, or the cc\ncommand, delivers the message to the maildir normally, but also associated the list of\nkeywords in KEYWORDS with the newly delivered message.\n\nKEYWORDS must be set before the message is delivered to a maildir. The contents of\nKEYWORDS are ignored, when delivering on an mbox folder.\n\nLINES\nNumber of lines in the current message. Note that this may be an approximation. It may or\nmay not take into account the -A option. Use this as criteria for filtering, nothing\nmore.\n\nMAILDIRQUOTA\nSet this variable in order to manually enforce a maximum size on ANY maildir where the\nmessage is delivered. This is an optional feature that must be enabled by the system\nadministrator, see maildirquota(8)[4] for more information.\n\nRETURNCODE\nThis variable is set when maildrop runs the system[5] command, xfilter[6] command, or a\ncommand that's specified within a pair of backtick characters ( command substitution ).\nThe RETURNCODE variable will be set to the exit code of the command, after it completes.\n\nSIZE\nNumber of bytes in the message. This may or may not include the -A option. Use this as a\ncriteria for filtering, nothing more.\n"
                },
                {
                    "name": "Unquoted text",
                    "content": "All text strings in filter files should be in single, or double quotes. However, for\nconvenience sake, quotes can be omitted under certain circumstances.\n\nText that includes ONLY letters, digits, and the following characters: -.:/${}@ may appear\nwithout quotes. Note that this does not allow spaces, or backslashes to be entered, however\nthe text is still variable-substituted, and the substituted text may contain other\ncharacters.\n\nAlso, note that patterns (see below) begin with the slash character. Normally, anything that\nbegins with the slash is interpreted as a pattern. However, text immediately after\n“VARIABLE=” is interpreted as a string even if it begins with a slash. This is why something\nlike:\n\nMAILDIR=/var/mail\n\n\nworks as expected. Using quotes, though, is highly recommended. You must use quotes to set a\nvariable to a lone slash, because an unquoted slash is interpreted as a division sign.\n\nLong double or singly-quoted text can be broken across multiple lines by ending the line with\na lone backslash character, like this:\n\nTEXT=\"This is a long \\\ntext string\"\n\n\nThe backslash, the newline, and all leading whitespace on the next line is removed, resulting\nin \"This is a long text string\".\n"
                },
                {
                    "name": "Command substitution",
                    "content": "Text enclosed in back-tick characters is interpreted as a shell command. The shell command is\nexecuted as a child process by maildrop. Its output is used in place of the command. For\nexample:\n\nDIR=`ls`\n\n\nplaces the names of the files in the current directory into the DIR variable.\n\nThe output of the command will have all newline characters replaced by spaces, and leading\nand trailing spaces will be stripped (multiple spaces are not removed, though). Also, the\ncontents of the message being delivered is made available to the command on standard input.\n"
                },
                {
                    "name": "Patterns",
                    "content": "The pattern syntax in maildrop is similar to the grep command's syntax, with some minor\ndifferences. A pattern takes the following form in the filter file:\n\n/pattern/:options\n\n\npattern specifies the text to look for in the message, in the UTF-8 codeset.  pattern must\nnot begin with a space, otherwise the leading slash will then be interpreted as a division\nsign. If you must search for text that starts with a space, use something like \"/[ ] ... /\".\n\nThe general syntax of maildrop's patterns is described in the pcrepattern(3) manual page,\nwith certain exceptions noted below.  maildrop uses the PCRE[7] library to implement pattern\nmatching. Not all features in PCRE are available in maildrop, and the “options” part, which\nfollows the pattern specification, changes the pattern matching further. Consult the\npcrepattern(3) manual page for more information, but note the following exceptions:\n\n•   Internal options settings are not supported (but see the “D” maildrop option, below). Do\nnot include option settings in the pattern, doing so will lead to undefined results.\n\n•   Named subpatterns are not implemented. Numbered subpatterns are implemented, see “Pattern\nMatch Results”, below.\n\n•   The search pattern gets executed not against the raw message text, but the message\ntranscoded into a canonical UTF-8-based format. This process involves transcoding any\nnon-UTF-8 message content into UTF-8. Additionally, message headers get converted into a\ncanonical format before the search pattern gets executed.\n\nFor structured headers with email addresses, the process involves removing extraneous\npunctuation, or adding missing ones (in situations where a missing punctuation character\ncan be deduced). Additionally certain pre-RFC822 obsolete header formats get converted to\ncanonical form.\n\nThis means that header search patterns that include punctuation character may appear not\nto work against obviously-matching message text. Use “reformime -u <message.txt”, with\nmessage.txt containing the sample message, to see exactly the actual text that gets\nsearched by patterns.\n"
                },
                {
                    "name": "Pattern options",
                    "content": "Following /pattern/, there may be an optional colon, followed by one. or more options. The\nfollowing options may be specified in any order:\n\nh\nMatch this pattern against the message header.\n\nb\nMatch this pattern against the message body.\n\nD\nThis is a case sensitive match. Normally the patterns match either uppercase or lowercase\ntext.  /john/ will match \"John\", \"john\", or \"JOHN\". Specify the D option for a\ncase-sensitive search: lowercase letters in the pattern must match lowercase letters in\nthe message; ditto for uppercase.\n\nIf neither 'h' or 'b' is specified, the pattern is matched against the header only.\nSpecifying the 'b' option causes the pattern to be matched against the message body.\nSpecifying both causes the pattern to be matched against the entire message.\n\nNormally, each line in the message gets matched against the pattern individually. When\napplying patterns to a header, multi-line headers (headers split on several lines by\nbeginning each continuation line with whitespace) are silently combined into a single line,\nbefore the pattern is applied.\n"
                },
                {
                    "name": "MIME encoding",
                    "content": "The pattern must be a valid text string in the UTF-8 codeset, and maildrop should handle\nmessages that use MIME encodings in other known character sets.  Options that specify a\nmessage header search result in maildrop searching the initial message headers, and any\nheaders of additional MIME sections, in a multipart MIME message. Options that specify a\nmessage body search will search through all \"text\" MIME content.\n\nFor a MIME search to succeed, the message must be a well-formed MIME message (with a\nMime-Version: 1.0 header).\n"
                },
                {
                    "name": "Weighted scoring",
                    "content": "Patterns are evaluated by maildrop as any other numerical expression. If a pattern is found,\nmaildrop's filter interprets the results of the pattern match as number 1, or true, for\nfiltering purposes. If a pattern is not found the results of the pattern search is zero. Once\na pattern is found, the search stops. Second, and subsequent occurrences of the same pattern\nare NOT searched for.\n\nmaildrop can also do weighted scoring. In weighted scoring, multiple occurrences of the same\npattern are used to calculate a numerical score.\n\nTo use a weighted search, specify the pattern as follows:\n\n/pattern/:options,xxx,yyy\n\n\nwhere xxx and yyy are two numbers.  yyy is optional -- it will default to 1, if missing.\n\nThe first occurrence of the pattern is evaluated as xxx. The second occurrence of the pattern\nis evaluated as xxx*yyy, the third as xxx*yyy*yyy, etc... All occurrences of the pattern are\nadded up to calculate the final score.\n\nNote\nmaildrop does not recognize multiple occurrences of the same pattern in the same line.\nMultiple occurences of the same pattern in one line count as one occurence.\n"
                },
                {
                    "name": "Pattern Match Results",
                    "content": "After a pattern is successfully matched, the actual text that is matched is placed in the\nMATCH variable. For example:\n\n/^From:.*/\n\n\nmatches a line of the form:\n\nFrom: postmaster@localhost\n\n\nHere the variable MATCH will be set to \"From: postmaster@localhost\", which can be used in\nsubsequent statements.\n\nIf the pattern contains subpatterns, the portions of the text that match the first subpattern\nis placed in the MATCH1 variable. The second subpattern, if any, is placed in MATCH2, and so\non:\n\n/^From:\\s+(.*)@(.*)/\n\n\nmatched against the same line will set MATCH to “From: postmaster@localhost”, MATCH1 to\n“postmaster”, and MATCH2 to “localhost”. Of course, in real world the “From:” header is\nusually much more complicated, and can't be handled that easily. This is just an illustrative\nexample.\n\nNote\nSubpatterns are not processed in the foreach statement.\n"
                },
                {
                    "name": "Conversion of maildrop 1.x patterns to 2.0",
                    "content": "Although the new PCRE-based pattern matching code in maildrop is completely different from\nthe built-in pattern matching code in maildrop 1.x, very few changes will be required to\nconvert recipes to the new syntax. The only major differences are:\n\n•   The subexpression format has changed. Any pattern that uses subexpression needs to be\nconverted. Additionally, references to MATCH2 must be replaced with MATCH1, MATCH3 to\nMATCH2, and so on. References to plain old MATCH will remain the same.\n\n•   The “w” pattern option is no longer possible, with PCRE. The very few recipes that use\nthis option, if any actually exist, will have to be rewritten in some other fashion.\n"
                },
                {
                    "name": "Expressions",
                    "content": "Although maildrop evaluates expressions numerically, results of expressions are stored as\ntext literals. When necessary, text literals are converted to numbers, then the results of a\nmathematical operation is converted back into a text literal.\n"
                },
                {
                    "name": "Operators",
                    "content": "The following operators carry their usual meaning, and are listed in order from lowest\nprecedence, to the highest:\n\n\n||\n&&\n<  <=  >  >=  ==  !=  lt  le  gt  ge  eq  ne\n|\n&\n+  -\n*  /\n=~ /pattern/\n/pattern/  !  ~  function()\n\n"
                },
                {
                    "name": "Variable assignment",
                    "content": "VARIABLE=expression\n\n\nAssigns the result of the expression to VARIABLE (note no leading $ in front of\nvariable).\n\nNote\nIf VARIABLE is NOT surrounded by quotes, then it may contain only letters, numbers,\nunderscores, dashes, and a selected few other characters. In order to initialize a\nvariable whose name contains non-standard punctuation marks, surround the name of the\nvariable with quotes.\n"
                },
                {
                    "name": "cc - deliver a copy of the message",
                    "content": "cc expression\n\n\nThe cc statement is very similar to the to statement, except that after delivering the\nmessage maildrop continues to process the filter file, unlike the to statement which\nimmediately terminates maildrop after the delivery is complete. Essentially, the message\nis carbon copied to the given mailbox, and may be delivered again to another mailbox by\nanother cc or to statement.\n\nSee the to statement[8] for more details. When cc is used to deliver a message to a\nprocess maildrop will set the EXITCODE variable to the process's exit code.\n"
                },
                {
                    "name": "dotlock - create a manual dot-lock",
                    "content": "dotlock expression {\n\n...\n\n}\n\n\nmaildrop automatically creates a lock when a message is delivered to a mailbox. Depending\nupon your system configuration, maildrop will use either dot-locks, or the flock() system\ncall.\n\nThe dotlock statement creates an explicit dot-lock file. Use the flock statement[9] to\ncreate an explicit flock() lock.\n\nThe expression is a filename that should be used as a lock file.  maildrop creates the\nindicated dot-lock, executes the filtering instructions contained within the { ... }\nblock, and removes the lock. The expression must be the name of the dot-lock file itself,\nNOT the name of the mailbox file you want to lock.\n\nNote\nWith manual locking, it is possible to deadlock multiple maildrop processes (or any\nother processes that try to claim the same locks).\n\nNo deadlock detection is possible with dot-locks, and since maildrop automatically\nrefreshes all of its dot-locks regularly, they will never go stale. You'll have\nmaildrop processes hanging in limbo, until their watchdog timers go off, aborting the\nmail delivery.\n"
                },
                {
                    "name": "echo - output diagnostic information",
                    "content": "echo expression\n\n\nmaildrop will print the given text. This is usually used when maildrop runs in embedded\nmode, but can be used for debugging purposes. Normally, a newline is printed after the\ntext. If text is terminated with a \\c, no newline will be printed.\n"
                },
                {
                    "name": "exception - trap fatal errors",
                    "content": "exception {\n\n...\n\n}\n\n\nThe exception statement traps errors that would normally cause maildrop to terminate. If\na fatal error is encountered anywhere within the block of statements enclosed by the\nexception clause, execution will resume immediately following the exception clause.\n"
                },
                {
                    "name": "exit - terminate filtering unconditionally",
                    "content": "exit\n\n\nThe exit statement immediately terminates filtering.  maildrop's return code is set to\nthe value of the EXITCODE variable. Normally, maildrop terminates immediately after\nsuccessfully delivering the message[8] to a mailbox. The exit statement causes maildrop\nto terminate without delivering the message anywhere.\n\nThe exit statement is usually used when maildrop runs in embedded mode[10], when message\ndelivery instructions are not allowed.\n"
                },
                {
                    "name": "flock - create an manual flock() lock",
                    "content": "flock expression {\n\n...\n\n}\n\n\nmaildrop automatically creates a lock when a message is delivered to a mailbox. Depending\nupon your system configuration, maildrop will use either dot-locks, or the flock() system\ncall.\n\nThe flock statement creates a manual flock() lock. Use the dotlock statement[11] to\ncreate a manual dot-lock file.\n\nThe expression is the name of the file that should be locked.  maildrop creates the lock\non the indicated file, executes the filtering instructions contained within the { ... }\nblock, and removes the lock.\n\nNote\nWith manual locking, it is possible to deadlock multiple maildrop processes (or any\nother processes that try to claim the same locks). The operating system will\nautomatically break flock() deadlocks. When that happens, one of the maildrop\nprocesses will terminate immediately. Use the exception statement in order to trap\nthis exception condition, and execute an alternative set of filtering instructions.\n"
                },
                {
                    "name": "foreach - iterate over text sections matched by a pattern",
                    "content": "foreach /pattern/:options\n{\n...\n}\n\nforeach (expression) =~ /pattern/:options\n{\n...\n}\n\n\nThe foreach statement executes a block of statements for each occurrence of the given\npattern in the given message, or expression. On every iteration MATCH variable will be\nset to the matched string. All the usual options may be applied to the pattern match,\nEXCEPT the following:\n\n,xxx,yyy\nWeighted scoring is meaningless, in this context.\n\n( ... )\nSubpatterns are not processed. Only the MATCH variable will be set for each found\npattern.\n"
                },
                {
                    "name": "if - conditional execution",
                    "content": "if (expression)\n{\n...\n}\nelse\n{\n...\n}\n\n\nConditional execution. If expression evaluates to a logical true (note - parenthesis are\nrequired) then the first set of statements is executed. The else keyword, and the\nsubsequent statements, are optional. If present, and the expression evaluates to a\nlogical false, the else part is executed.\n\nmaildrop evaluates all expression as text strings. In the context of a logical\nexpression, an empty string, or the number 0 constitutes a logical false value, anything\nelse is a logical true value.\n\nIf the if part, or the else part consists of only one statement, the braces may be\nomitted.\n\nNote\nThe grammar of this if statement is stricter than usual. If you get baffling syntax\nerrors from maildrop, make sure that the braces, and the if statement, appear on\nseparate lines. Specifically: the closing parenthesis, the closing braces, and the\nelse statement, must be at the end of the line (comments are allowed), and there may\nnot be any blank lines in between (not even ones containing comments only).\n\nIf the else part contains a single if, and nothing else, this may be combined into an\nelsif:\n\nif (expression)\n{\n...\n}\nelsif (expression)\n{\n...\n}\n\n\nThe above example is logically identical to:\n\nif (expression)\n{\n...\n}\nelse\n{\nif (expression)\n{\n...\n}\n}\n\n\nConsecutive elsif sequences are allowed:\n\nif (expression)\n{\n...\n}\nelsif (expression)\n{\n...\n}\nelsif (expression)\n{\n...\n}\n\n\nConsecutive occurences of elsif commands eliminate a significant amount of indentation,\nand the resulting code is more readable.\n"
                },
                {
                    "name": "import - access original environment variable",
                    "content": "import variable\n\n\nWhen maildrop starts, it normally imports the contents of the environment variables, and\nassigns them to internal maildrop variables. For example, if there was an environment\nvariable FOO, the internal maildrop variable FOO will have the contents of the\nenvironment variable. From then on, FOO will be no different than any other variable, and\nwhen maildrop runs an external command, the contents of maildrop's variables will be\nexported as the environment for the command.\n\nCertain variables, like HOME and PATH, are always reset to fixed defaults, for security\nreasons. Also, in delivery and embedded modes, the environment is not imported at all\n(with the exception of system locale environment variables), and maildrop starts with\nonly the fixed default variables.\n\nThe import statement initializes the specified variable with the contents of the original\nenvironment variable when maildrop started. For example:\n\necho \"PATH is $PATH\"\nPATH=\"/bin\"\necho \"PATH is $PATH\"\nimport PATH\necho \"PATH is $PATH\"\nexit\n\n\nThis results in the following output:\n\nPATH is /bin:/usr/bin:/usr/local/bin\nPATH is /bin\nPATH is /home/root/bin:/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin\n\n\nThis shows that when maildrop starts PATH is set to the fixed default of\n/bin:/usr/bin:/usr/local/bin. However, the original contents of the PATH environment\nvariable we different, and the import statement shows what it was.\n"
                },
                {
                    "name": "include - execute filtering instructions from another file",
                    "content": "include expression\n\n\nThe include statement reads a file, and executes filtering instructions contained in that\nfile. Note that the include statement is processed when the current filter file is being\nexecuted. When maildrop reads the initial filter file, any syntax errors in the filtering\ninstructions are immediately reported, and maildrop will terminate with a return code of\nEXTEMPFAIL. Any errors in files specified by include statements are NOT reported,\nbecause those files will not be read until the include statement is itself executed.\n\nIf the specified file does not exist, or if there are any syntax errors in the file,\nmaildrop reports the error, and terminates with a return code of EXTEMPFAIL.\n"
                },
                {
                    "name": "log, logfile - log message deliveries",
                    "content": "logfile expression\n\nlog expression\n\n\nLogging in maildrop is normally turned off. The logfile statement specifies the file\nwhere maildrop will log how the message has been disposed of. The parameter is then name\nof the file. If the file exists maildrop appends to the file.\n\nFor each delivery (the to[8] and cc[12] statements, and default deliveries) maildrop\nrecords the From: and the Subject: fields, together with the current time, in the log\nfile.\n\nThe log statement adds additional logging text to the log file. The log statement works\nexactly like the echo statement, except that the text is written to the logfile, instead\nof standard output.\n"
                },
                {
                    "name": "system - execute a system command",
                    "content": "system expression\n\n\nexpression specifies an external program that maildrop runs as a subprocess. The\nsubprocess's standard input gets connected to /dev/null, and the subprocess inherits the\nstandard output and error from maildrop.\n"
                },
                {
                    "name": "to - deliver message to a mailbox",
                    "content": "to expression\n\n\nThe to statement delivers the message to a mailbox.  expression must evaluate to a valid\nmailbox. A valid mailbox is either a mailbox file, a maildir, or an external program\n(which includes forwarding to another address).\n\nThe to statement is the final delivery statement.  maildrop delivers message, then\nimmediately terminates, with its return code set to the EXITCODE variable. If there was\nan error while delivering the message, maildrop terminates with the EXTEMPFAIL exit\ncode. A properly-written mail transport agent should re-queue the message, and re-attempt\ndelivery at some later time.\n\nAn expression that begins with the \"|\" character specifies an external program to run to\nhandle the actual delivery. The SHELL variable specifies the shell to execute the given\ncommand. The message is provided to the command on standard input.  maildrop's exit code\nwill be the process's exit code.\n\nAn expression that begins with an exclamation mark, \"!\" specifies a whitespace-delimited\nlist of E-mail addresses to forward the message to. The program specified by the SENDMAIL\nvariable is run as an external program, with the list of E-mail addresses provided as\nparameters to the program.\n\nOtherwise, expression names the mailbox where maildrop delivers the message. If\nexpression is a directory, maildrop assumes that the directory is a maildir directory.\nOtherwise, maildrop will deliver the message to a file, formatted in traditional mailbox\nformat.  maildrop will use either dot-locking, or flock()-locking when delivering the\nmessage to the file.\n"
                },
                {
                    "name": "while - repeatedly execute a block of statements",
                    "content": "while (expression)\n{\n...\n}\n\n\nThe expression is repeatedly evaluated. Each time it evaluates to a logical true[13], the\nstatements inside the braces are executed. When expression evaluates to a logical false,\nthe while loop is over. Take care to avoid infinite loops.\n"
                },
                {
                    "name": "xfilter - filter message through another program",
                    "content": "xfilter expression\n\n\nexpression specifies an external program that maildrop runs to filter the current\nmessage. The current message will be piped to the filter program as standard input. The\noutput of the filter program replaces the current message being delivered. The external\nprogram must terminate with an exit code of 0. If the external program does not terminate\nwith an exit code of 0, or if it does not read the message from the standard input,\nmaildrop terminates with an exit code of EXTEMPFAIL.\n"
                },
                {
                    "name": "|| - logical or",
                    "content": "expression1 || expression2\n\n\n\nIf expression1 evaluates to a logical true, the result of the || is expression1,\notherwise it's expression2, which is evaluated.\n\nmaildrop uses the following concept of true/false: an empty text literal, or a text\nliteral that consists of the single character \"0\" is a logical false value. Anything else\nis a logical true value.\n"
                },
                {
                    "name": "&& - logical and",
                    "content": "expression1 && expression2\n\n\n\nIf expression1 evaluates to a logical false, the result of the && is expression1,\notherwise it's expression2, which is evaluated.\n\nmaildrop uses the following concept of true/false: an empty text literal, or a text\nliteral that consists of the single character \"0\" is a logical false value. Anything else\nis a logical true value.\n"
                },
                {
                    "name": "<, <=, >, >=, ==, != - numerical comparison",
                    "content": "expression1 < expression2\n\nexpression1 <= expression2\n\nexpression1 > expression2\n\nexpression1 >= expression2\n\nexpression1 == expression2\n\nexpression1 != expression2\n\n\n\nThese operators compare their left hand side expression against their right hand side.\nThese operators compare the numerical values of each side, as floating point numbers. If\nthe numbers compare as indicated, the result of the comparison is the text string \"1\",\notherwise it is the text string 0.\n\nNote\nCcomparisons are not associative: \"a < b < c\" is an error. If it is absolutely\nnecessary, use \"(a < b) < c\".\n"
                },
                {
                    "name": "lt, le, gt, ge, eq, ne - text comparison",
                    "content": "expression1 lt expression2\n\nexpression1 le expression2\n\nexpression1 gt expression2\n\nexpression1 ge expression2\n\nexpression1 eq expression2\n\nexpression1 ne expression2\n\n\n\nThese operators compare their left hand side expression against their right hand side.\nThese operators compare each side as text strings (alphabetically, although the text may\ninclude anything). If the text strings compare as indicated, the result of the comparison\nis the text string \"1\", otherwise it is the text string 0.\n\nNote\nComparisons are not associative: \"a lt b lt c\" is an error. If it is absolutely\nnecessary, use \"(a lt b) lt c\". (But why would you?).\n"
                },
                {
                    "name": "| - bitwise or",
                    "content": "expression1 | expression2\n\n\nThis is the bitwise or operator. Its result is a 32 bit integer, which is a bitwise-or\ncombination of the left hand side and the right hand side.\n"
                },
                {
                    "name": "& - bitwise and",
                    "content": "expression1 & expression2\n\n\nThis is the bitwise and operator. Its result is a 32 bit integer, which is a bitwise-and\ncombination of the left hand side and the right hand side.\n\n+, -, *, / - numerical operations\nexpression1 + expression2\n\nexpression1 - expression2\n\nexpression1 * expression2\n\nexpression1 / expression2\n\n\n\nThese are numerical, floating point, operators.\n"
                },
                {
                    "name": "=~ /pattern/:options - pattern match against string",
                    "content": "expression =~ /pattern/:option\n\n\nThe left hand side of the =~ operator can be any expression. The right hand side is\nalways a pattern specification. The result of the operator is the weighted match of the\npattern against expression (if the options do not specify weighted scoring, the result is\nsimply 1 if the pattern was found, 0 if not).\n\nSee \"Patterns[14]\" for more information.\n"
                },
                {
                    "name": "/pattern/:options - pattern match against message",
                    "content": "/pattern/:option\n\n\nThe result of this operator is the weighted match of the pattern against the current\nmessage (if the options do not specify weighted scoring, the result is simply 1 if the\npattern was found, 0 if not).\n\nSee \"Patterns[14]\" for more information.\n"
                },
                {
                    "name": "!, ~ - logical/bitwise not operator.",
                    "content": "! expression\n\n~ expression\n\n\nThe result of the !  operator is a logical opposite of its right hand side expression. If\nthe right hand side expression evaluated to a logical true, the result is a logical\nfalse. If it evaluated to a logical false, the result is a logical true.\n\nmaildrop uses the following concept of true/false: an empty text literal, or a text\nliteral that consists of the single character \"0\" is a logical false value. Anything else\nis a logical true value.\n\nThe result of the ~ operator is a bitwise complement of its right hand side expression.\nThe right hand side expression is evaluated as a 32 bit integer, and the result of this\noperator is a bitwise complement of the result.\n"
                },
                {
                    "name": "escape(string) - escape special characters in a string.",
                    "content": "escape(expression)\n\n\nThe escape function returns its sole argument with every occurrence of a special\ncharacter prefixed by a backslash. A special character is any of the following\ncharacters:\n\n|!$()[]\\+*?.&;`'-~<>^{}\"\n\n\nThis can used when matching pattern sections[15], and then taking one section and\nmatching it again. For example:\n\nif ( /^From:\\s*(.*)/ )\n{\nMATCH1=escape($MATCH1)\nif ( /^Subject:.*$MATCH1/ )\n{\n...\n}\n}\n\n\nThis example checks if the contents of the From: header can also be found in the Subject:\nheader. If the escape function were not used, then any special characters in the From:\nheader that are also used in regular expressions, such as * or +, would introduce\nunpredictable behavior, most likely a syntax error.\n\nThe reason why this list of special characters also includes characters not used in\nmaildrop's regular expressions is to allow maildrop's variables to be used on the command\nline of a shell command executed by the xfilter command, backtick characters, or to or cc\ncommands.\n\nAlthough using data from an external data source is dangerous, and it may result in\ninadvertent exploits, using the escape function should hopefully result in fewer\nsurprises.\n"
                },
                {
                    "name": "gdbmopen, gdbmclose, gdbmfetch, gdbmstore - GDBM support in maildrop",
                    "content": "These functions provide support for GDBM database files. See maildropgdbm(5)[16] for more\ninformation.\n\nNote\nThe system administrator can disable GDBM support in maildrop, so these commands may\nnot be available to you.\n"
                },
                {
                    "name": "getaddr(string) - extract RFC 2822 addresses from a header.",
                    "content": "if ( /^From:\\s*(.*)/ )\n{\nADDR=getaddr($MATCH1)\n}\n\n\nThis function is usually applied to a header that contains RFC 2822[17] addresses. It\nextracts the actual addresses from the header, without any comments or extraneous\npunctuation. Each address is followed by a newline character. For example, if string\ncontains:\n\njoe@domain.com (Joe Brown), \"Alex Smith\" <alex@domain.com>, tom@domain.com\n\n\nThe result of the getaddr function is the following string:\n\njoe@domain.com<NL>alex@domain.com<NL>tom@domain.com<NL>\n\n\nNote\nBecause getaddr() interprets RFC 2822[18] loosely, it is not necessary to strip off\nthe \"To:\" or the \"Cc:\" header from the string, before feeding it to getaddr(). For\nexample, the following snippet of code takes all addresses in the message, and\nconcatenates them into a single string, separated by spaces:\n\nADDRLIST=\"\"\nforeach /^(To|Cc): .*/\n{\nforeach (getaddr $MATCH) =~ /.+/\n{\nADDRLIST=\"$ADDRLIST $MATCH\"\n}\n}\n\n\nNote\nIn certain rare situations, RFC 2822[18] allows spaces to be included in E-mail\naddresses, so this example is just educational.\n"
                },
                {
                    "name": "hasaddr(string) - Search for an address.",
                    "content": "if ( hasaddr(string) )\n{\n...\n}\n\n\n\"string\" is of the form user@domain. The hasaddr function returns 1 if this address is\nincluded in any To:, Cc:,Resent-To:, or Resent-Cc:, header in the message, otherwise this\nfunction returns 0.\n\nThis is more than just a simple text search. Each header is parsed according to RFC822.\nAddresses found in the header are extracted, ignoring all comments and names. The\nremaining addresses are checked, and if \"string\" is one of them, hasaddr returns 1,\notherwise it returns 0.\n\nThe comparison is case-insensitive. This actually violates RFC822 (and several others) a\nlittle bit, because the user part of the address may be (but is not required to be) case\nsensitive.\n"
                },
                {
                    "name": "length (string) - length of a string",
                    "content": "if (length(string) > 80)\n{\n...\n}\n\n\nThe length function returns the number of characters in string.\n"
                },
                {
                    "name": "lookup (expr, 'filename', 'options') - read file for patterns",
                    "content": "if (lookup(expr, file, \"option\"))\n{\n...\n}\n\n\nexpr is any expression.  filename is a name of a file containing a list of patterns. Note\nthat filename is relative to the current directory, which is the home directory of the\nuser when maildrop runs in delivery mode, or embedded mode.  maildrop then reads the\nfile. Blank lines will be ignored, as well as any lines that begin with the # character\n(comments).\n\nLeading whitespace (but not trailing whitespace, take care) is removed, and the remaining\ncontents of each line are interpreted as a pattern which is matched against expr. As soon\nas the match is found, lookup returns \"1\". If no match is found after reading the entire\nfile, lookup returns \"0\". For example:\n\nif ( /^To:\\s*(.*)/ && lookup( $MATCH1, \"badto.dat\" ))\n{\nexit\n}\n\n\nThe file badto.dat contains the following two lines:\n\nfriend@public\n^[^@]*$\n\n\nIf a message has a To: header that contains the text \"friend@public\", or does not contain\nat least one @ character, then the message will be silently dropped on the floor (\nmaildrop will terminate without delivering the message anywhere).\n\noptions are the pattern matching options to use. The only supported option is \"D\" (the\nrest are meaningless, in this case).\n\nNote\nBe careful with discarding messages like that. Pattern matching can be tricky, and a\nslight miscalculation can cause mail to be unintentionally discarded. It is much\ndesirable to first deliver message to a separate folder or mailbox, and once the\nfilter is verified to work correctly, change it so the messages are discarded\ncompletely.\n"
                },
                {
                    "name": "substr(string,start [,count]) - return substring",
                    "content": "foo=substr($foo, 1, 10)\n\n\nThe substr function extracts characters from string beginning with character #start. If\ncount is specified, at most count characters starting at position start are kept, any\nexcess is trimmed.\n"
                },
                {
                    "name": "time - return current time",
                    "content": "foo=time\n\n\nThe time function returns the current time, in seconds, since January 1, 1970. This\nfunction is useful when using GDBM files. See maildropex(7)[19] for an example of using\nthe time function.\n"
                },
                {
                    "name": "tolower(string) - Convert string to lowercase.",
                    "content": "foo=tolower(string)\n\n\nThis function returns the string with all uppercase characters replaced by lowercase\ncharacters.\n"
                },
                {
                    "name": "toupper(string) - Convert string to uppercase.",
                    "content": "foo=toupper(string)\n\n\nThis function returns the string with all lowercase characters replaced by uppercase\ncharacters.\n"
                },
                {
                    "name": "Statements",
                    "content": "The filter file is read by maildrop ($HOME/.mailfilter or another file), and it contains\nfiltering statements, one per line. The filtering language used by maildrop has a loosely -\ndefined grammatical structure.\n\nStatements are listed one per line. Multiple statements may be listed on the same line by\nseparating them with semicolons. To continue a long statement on the next line, terminate the\nline with a backslash character.\n"
                }
            ]
        },
        "BUGS": {
            "content": "If getaddr() or hasaddr() functions are used on broken headers, the results are\nunpredictable.\n\nhasaddr() is completely case insensitive. This actually violates a few RFCs, because the\nuserid portion of the address could be case-sensitive, but it's not in too many cases, so\nthere.\n",
            "subsections": []
        },
        "SEE ALSO": {
            "content": "lockmail(1)[20], maildrop(1)[21], maildropgdbm(5)[16], maildirquota(8)[4], reformail(1)[22],\negrep(1), sendmail(8).\n",
            "subsections": []
        },
        "AUTHOR": {
            "content": "",
            "subsections": [
                {
                    "name": "Sam Varshavchik",
                    "content": "Author\n"
                }
            ]
        },
        "NOTES": {
            "content": "1. Courier mail server\nhttp://www.courier-mta.org/\n\n2. dot-courier(5)\nhttp://www.courier-mta.org/maildrop/dot-courier.html\n\n3. value of the -M option\nhttp://www.courier-mta.org/maildrop/maildrop.html#moption\n\n4. maildirquota(8)\nhttp://www.courier-mta.org/maildrop/maildirquota.html\n\n5. system\nhttp://www.courier-mta.org/maildrop/#system\n\n6. xfilter\nhttp://www.courier-mta.org/maildrop/#xfilter\n\n7. PCRE\nhttp://www.pcre.org\n\n8. See the to statement\nhttp://www.courier-mta.org/maildrop/#to\n\n9. flock statement\nhttp://www.courier-mta.org/maildrop/#flock\n\n10. embedded mode\nhttp://www.courier-mta.org/maildrop/maildrop.html#embedded\n\n11. dotlock statement\nhttp://www.courier-mta.org/maildrop/#dotlock\n\n12. cc\nhttp://www.courier-mta.org/maildrop/#cc\n\n13. evaluates to a logical true\nhttp://www.courier-mta.org/maildrop/#if\n\n14. Patterns\nhttp://www.courier-mta.org/maildrop/#patterns\n\n15. matching pattern sections\nhttp://www.courier-mta.org/maildrop/#patmatch\n\n16. maildropgdbm(5)\nhttp://www.courier-mta.org/maildrop/maildropgdbm.html\n\n17. RFC 2822\nhttp://www.rfc-editor.org/rfc/rfc2822.txt\n\n18. RFC 2822\nhttp://www.rfc-editor.org/rfc/rfc822.txt\n\n19. maildropex(7)\nhttp://www.courier-mta.org/maildrop/maildropex.html\n\n20. lockmail(1)\nhttp://www.courier-mta.org/maildrop/lockmail.html\n\n21. maildrop(1)\nhttp://www.courier-mta.org/maildrop/maildrop.html\n\n22. reformail(1)\nhttp://www.courier-mta.org/maildrop/reformail.html\n\n\n\nCourier Mail Server                          07/24/2017                            MAILDROPFILTER(7)",
            "subsections": []
        }
    },
    "summary": "maildropfilter - maildrop's filtering language",
    "flags": [],
    "examples": [],
    "see_also": [
        {
            "name": "lockmail",
            "section": "1",
            "url": "https://www.chedong.com/phpMan.php/man/lockmail/1/json"
        },
        {
            "name": "maildrop",
            "section": "1",
            "url": "https://www.chedong.com/phpMan.php/man/maildrop/1/json"
        },
        {
            "name": "maildropgdbm",
            "section": "5",
            "url": "https://www.chedong.com/phpMan.php/man/maildropgdbm/5/json"
        },
        {
            "name": "maildirquota",
            "section": "8",
            "url": "https://www.chedong.com/phpMan.php/man/maildirquota/8/json"
        },
        {
            "name": "reformail",
            "section": "1",
            "url": "https://www.chedong.com/phpMan.php/man/reformail/1/json"
        },
        {
            "name": "egrep",
            "section": "1",
            "url": "https://www.chedong.com/phpMan.php/man/egrep/1/json"
        },
        {
            "name": "sendmail",
            "section": "8",
            "url": "https://www.chedong.com/phpMan.php/man/sendmail/8/json"
        }
    ]
}