MIMEDEFANG-FILTER(5)

NAME
mimedefang-filter - Configuration file for MIMEDefang mail filter.

DESCRIPTION
mimedefang-filter is a Perl fragment which controls how mimedefang.pl disposes of various parts of a MIME message. In addition, it contains some global variable settings which affect the operation of mimedefang.pl.

CALLING SEQUENCE
Incoming e-mail is handled as follows:

1) A temporary working directory is created. It is made the current working directory and the e-mail message is split into parts in this directory.

2) If the file /usr/local/etc/mimedefang/mimedefang-filter.pl defines a Perl function called filter_begin, it is called with no arguments. Any return value is ignored.

3) For each leaf part of the mail message, filter is called with four arguments: entity, a MIME::Entity object; fname, the suggested filename taken from the MIME Content-Disposition header; ext, the file extension, and type, the MIME Content-Type value. For each non-leaf part of the mail message, filter_multipart is called with the same four arguments as filter. A non-leaf part of a message is a part which contains nested parts. Such a part has no useful body, but you should still perform filename checks to check for viruses which use malformed MIME to masquerade as non-leaf parts (like message/rfc822). In general, any action you perform in filter_multipart applies to the part itself and any contained parts.

4) After all parts have been processed, the function filter_end is called if it has been defined. It is passed a single argument consisting of the (possibly modfied) MIME::Entity object representing the message about to be delivered.

DISPOSITION
mimedefang.pl examines each part of the MIME message is examined and chooses a disposition. Unless otherwise indicated, the dispositions should be called only from filter and not filter_begin or filter_end.

The available dispositions are:

accept
    The part is passed through unchanged.

accept_with_warning
    The part is passed through unchanged, but a warning is added to the mail message.

drop
    The part is deleted without any notification to the recipients.

drop_with_warning
    The part is deleted and a warning is added to the mail message.

replace_with_warning
    The part is deleted and instead replaced with a text message.

defang
    The part is passed through unchanged, but its MIME type and filename are changed to values which make social engineering attacks harder.

quarantine
    The part is deleted and a warning is added to the mail message. In addition, a copy of the part is saved on the mail server and a notification is sent to the MIMEDefang administrator.

bounce
    The entire e-mail message is rejected and an error returned to the sender. The intended recipients are not notified.

discard
    The entire e-mail message is discarded silently. Neither the sender nor the intended recipients are notified.

CONTROLLING RELAYING
If you use mimedefang-multiplexor, you can define an additional function called filter_relay in your filter. This lets you reject SMTP connection attempts early on in the SMTP dialog, rather than waiting until the whole message has been sent. Note that for this check to take place, you must use the -r flag with mimedefang.

In non-multiplexor mode, filter_relay is ignored.

filter_relay is passed two arguments: $hostip is the IP address of the relay host (for example, "127.0.0.1") and $hostname is the host name if known (for example, "localhost.localdomain"). If the host name could not be determined, $hostname is simply a copy of $hostip.

filter_relay must return a two-element list. The first element is 0 if the connection should be rejected, or one if accepted. The second element is an error message to return in the SMTP dialog in the case of rejection. The message must not contain newlines.

For example, if you wish to reject connection attempts from any machine in the spammer.com domain, you could use this function:
sub filter_relay {
	my ($ip, $name) = @_;
	if ($name =~ /spammer.com$/) {
		return (0, "Sorry; spammer.com is blacklisted");
	}
	return (1, "ok");
}

FILTERING BY SENDER
If you use mimedefang-multiplexor, you can define an additional function called filter_sender in your filter. This lets you reject messages from certain senders, rather than waiting until the whole message has been sent. Note that for this check to take place, you must use the -s flag with mimedefang.

In non-multiplexor mode, filter_sender is ignored.

filter_sender is passed three arguments: $sender is the envelope e-mail address of the sender (for example, "<dfs@roaringpenguin.com>"). The address may or may not be surrounded by angle brackets. $ip and $name are the IP address and host name of the SMTP relay.

filter_sender must return a two-element list. The first element is 0 if the message should be rejected, or one if accepted. The second element is an error message to return in the SMTP dialog in the case of rejection. The message must not contain newlines.

For example, if you wish to reject messages from spammer@badguy.com, you could use this function:
sub filter_sender {
	my ($sender, $ip, $hostname) = @_;
	if ($sender =~ /^<?spammer@badguy.com>?$/i) {
		return (0, 'Sorry; spammer@badguy.com is blacklisted.');
	}
	return (1, "ok");
}

FILTERING BY RECIPIENT
If you use mimedefang-multiplexor, you can define an additional function called filter_recipient in your filter. This lets you reject messages to certain recipients, rather than waiting until the whole message has been sent. Note that for this check to take place, you must use the -t flag with mimedefang.

In non-multiplexor mode, filter_recipient is ignored.

filter_recipient is passed four arguments: $recipient is the envelope address of the recipient and $sender is the envelope e-mail address of the sender (for example, "<dfs@roaringpenguin.com>"). The addresses may or may not be surrounded by angle brackets. $ip and $name are the IP address and host name of the SMTP relay.

filter_recipient must return a two-element list. The first element is 0 if the message should be rejected, or one if accepted. The second element is an error message to return in the SMTP dialog in the case of rejection. The message must not contain newlines.

For example, if you wish to reject messages from spammer@badguy.com, unless they are to postmaster@mydomain.com, you could use this function:
sub filter_recipient {
	my ($recipient, $sender, $ip, $hostname) = @_;
	if ($sender =~ /^<?spammer@badguy.com>?$/i) {
		if ($recipient =~ /^<?postmaster@mydomain.com>?$/i) {
			return (1, "ok");
		}
		return (0, 'Sorry; spammer@badguy.com is blacklisted.');
	}
	return (1, "ok");
}

GLOBAL VARIABLES
The following Perl global variables should be set in mimedefang-filter:

$AdminAddress
    The e-mail address of the MIMEDefang administrator.

$DaemonAddress
    The e-mail address from which MIMEDefang-originated notifications come.

$AddWarningsInline
    If this variable is set to 0, then all MIMEDefang warnings (such as created by action_quarantine or action_drop_with_warning) are collected together and added in a separate MIME part called WARNING.TXT. If the variable is set to 1, then the warnings are added directly in the first text/plain and text/html parts of the message. If the message does not contain any text/plain or text/html parts, then a WARNING.TXT MIME part is added as before.

$Stupidity{"flatten"}
    Set this to 1 if your e-mail client is too stupid to understand nested MIME messages (that is, MIME messages which may contain parts of type multipart/*).

$Stupidity{"NoMultipleInlines"}
    Set this to 1 if your e-mail is too stupid to display multiple MIME parts in-line. In this case, a nasty hack causes the first part of the original message to appear as an attachment if warning are issued. Mail clients which are not this stupid are Netscape Communicator and Pine. On the other hand, Microsoft Exchange and Microsoft Outlook are indeed this stupid. Perhaps users of those clients should switch. The following global variables may optionally be set. If they are not set, sensible defaults are used:

$DaemonName (default "MIMEDefang")
    The full name used when MIMEDefang sends out notifications.

$AdminName (default "MIMEDefang Administrator")
    The full name of the MIMEDefang administrator.

$SALocalTestsOnly (default 1)
    If set to 1, SpamAssassin calls will use only local tests. This is the default and recommended setting. This disables Received, RBL and Razor tests in an all or nothing fashion. To use Razor this MUST be set to 0. You can add 'skip_rbl_checks 1' to your SpamAssassin config file if you need to.

$NotifySenderSubject (default "MIMEDefang Notification")
    The subject used when e-mail is sent out by action_notify_sender(). If you set this, you should set it each time you call action_notify_sender() to ensure consistency.

$NotifyAdministratorSubject (default "MIMEDefang Notification")
    The subject used when e-mail is sent out by action_notify_administrator(). If you set this, you should set it each time you call action_notify_administrator() to ensure consistency.

$QuarantineSubject (default "MIMEDefang Quarantine Report")
    The subject used when a quarantine notice is sent to the adminsitrator. If you set this, you should set it each time you call action_quarantine() or action_quarantine_entire_message().

$NotifyNoPreamble (default 0)
    Normally, notifications sent by action_notify_sender() have a preamble warning about message modifications. If you do not want this, set $NotifyNoPreamble to 1.

$OpenAVHost (default 127.0.0.1:8127)
    Host used for OpenAV daemon calls within message_contains_virus_openantivirus and entity_contains_virus_openantivirus unless a host is provided by the calling routine.

$SophieSock (default /var/spool/MIMEDefang/sophie)
    Socket used for Sophie daemon calls within message_contains_virus_sophie and entity_contains_virus_sophie unless a socket is provided by the calling routine.

FILTER
The heart of mimedefang-filter is the filter procedure. See the examples which came with MIMEDefang to learn to write a filter. The filter is called with the following arguments:

$entity
    The MIME::Entity object. (See the MIME::tools Perl module documentation.)

$fname
    The suggested attachment filename, or "" if none was supplied.

$ext
    The file extension (all characters from the rightmost period to the end of the filename.)

$type
    The MIME type (for example, "text/plain".)

The filename is derived as follows:

o   First, if the Content-Disposition header has a "filename" field, it is used.

o   Otherwise, if the Content-Type header has a "name" field, it is used.

o   Otherwise, the Content-Description header value is used.

Note that the truly paranoid will check all three fields for matches. The functions re_match and re_match_ext perform regular expression matches on all three of the fields named above, and return 1 if any field matches. See the sample filters for details. The calling sequence is:
	re_match($entity, "regexp")
	re_match_ext($entity, "regexp")
re_match returns true if any of the fields matches the regexp without regard to case. re_match_ext returns true if the extension in any field matches. An extension is defined as the last dot in a name and all remaining characters.

In addition, the following global variables are available:

%Features
    This hash lets you determine at run-time whether certain functionality is available. The defined features are: $Features{"SpamAssassin"} is 1 if SpamAssassin 1.6 or better is installed; 0 otherwise. $Features{"HTMLCleaner"} is 1 if Anomy::HTMLCleaner is installed; 0 otherwise. $Features{"File::Scan"} is 1 if File::Scan is installed; 0 otherwise. $Features{"HTML::Parser"} is 1 if HTML::Parser is installed; 0 otherwise. $Features{"Virus:FileScan"} is a copy of $Features{"File::Scan"}. $Features{"Virus:OpenAV"} is provided for completeness and is currently always 1. May be 0 in future if a suitable test can be created. $Features{"Virus:NAI"} is the full path to NAI uvscan if it is installed; 0 if it is not. $Features{"Virus:HBEDV"} is the full path to H+BEDV AntiVir if it is installed; 0 if it is not. $Features{"Virus:SOPHOS"} is the full path to Sophos sweep if it is installed; 0 if it is not. $Features{"Virus:AVP"} is the full path to AVP AvpLinux if it is installed; 0 if it is not. $Features{"Virus:FSAV"} is the full path to F-Secure fsav if it is installed; 0 if it is not. $Features{"Virus:RAV"} is the full path to Reliable AntiVirus ravav if it is installed; $Features{"Virus:FPROT"} is the full path to F-Risk f-prot if it is installed; 0 if it is not. $Features{"Virus:SOPHIE"} is the full path to Sophie if it is installed; 0 if it is not. NOTE: PERL module based features (SpamAssassin, HTMLCleaner and Virus:FileScan) are determined at runtime and may change as these are added and removed. Most Virus features are predetermined at the time of configuration and do not adapt to runtime availability unless changed by the filter rules.

$SuspiciousCharsInHeaders
    If this variable is true, then mimedefang has discovered suspicious characters in message headers. This might be an exploit for bugs in MIME-parsing routines in some badly-written mail user agents (e.g. Microsoft Outlook.) You should always drop such messages.

$SuspiciousCharsInBody
    If this variable is true, then mimedefang has discovered suspicious characters in the message body. This might be an exploit for bugs in MIME-parsing routines in some badly-written mail user agents (e.g. Microsoft Outlook.) You should always drop such messages.

$RelayHostname
    The host name of the relay. This is the name of the host which is attempting to send e-mail to your host. May be "undef" if the host name could not be determined.

$RelayAddr
    The IP address of the sending relay (as a string consisting of four dot-separated decimal numbers.) One potential use of $RelayAddr is to limit mailing to certain lists to people within your organization.

$Subject
    The contents of the "Subject:" header.

$Sender
    The sender of the e-mail

@Recipients
    A list of the recipients.

$MessageID
    The contents of the "Message-ID:" header if one is present. Otherwise, contains the string "<No-Message-ID>"

$QueueID
    The Sendmail queue identifier if it could be determined. Otherwise, contains the string "<No-Queue-ID>"

$MsgID
    Set to $QueueID if the queue ID could be determined; otherwise, set to $MessageID. This identifier should be used in logging, because it matches the identifier used by Sendmail to log messages.

$VirusScannerMessages
    Each time a virus-scanning function is called, messages (if any) from the virus scanner are accumulated in this variable. You can use it in filter_end to formulate a notification (if you wish.)

$SASpamTester
    If defined, this is the configured Mail::SpamAssassin object used for mail tests. It may be initialized with a call to spam_assassin_init which also returns it.

%SendmailMacros
    This hash contains the values of some Sendmail macros. The hash elements exist only for macros defined by Sendmail. See the Sendmail documentation for the meanings of the macros. By default, mimedefang passes the values of the following macros: ${daemon_name}, ${if_name}, ${if_addr}, $j, $_, $i, ${tls_version}, ${cipher}, ${cipher_bits}, ${cert_subject}, ${cert_issuer}, ${auth_type}, ${auth_authen}, ${auth_ssf}, ${auth_author}, ${mail_mailer}, ${mail_host} and ${mail_addr}. If any macro is not set or not passed to milter, it will be unavailable. To access the value of a macro, use:
    	$SendmailMacros{"macro_name"}
    Do not place curly brackets around the macro name.

ACTIONS
When the filter procedure decides how to dispose of a part, it should call one or more action_ subroutines. The action subroutines are:

action_accept()
    Accept the part.

action_rebuild()
    Rebuild the mail body, even if mimedefang thinks no changes were made. Normally, mimedefang does not alter a message if no changes were made. action_rebuild may be used if you make changes to entities directly (by manipulating the MIME::Head, for example.) Unless you call action_rebuild, mimedefang will be unaware of the changes. Note that all the built-in action... routines which change a message implicitly call action_rebuild.

action_add_header($hdr, $val)
    Add a header from the message. This can be used in filter_begin or filter_end. The $hdr component is the header name without the colon, and the $val is the header value. For example, to add the header:
    	X-MyHeader: A nice piece of text
    use:
    	action_add_header("X-MyHeader", "A nice piece of text");

action_change_header($hdr, $val)
    Changes an existing header in the message. This can be used in filter_begin or filter_end. The $hdr component is the header name without the colon, and the $val is the header value. If the header does not exist, then a header with the given name and value is added.

action_drop()
    Drop the part. If called from filter_multipart, drops all contained parts also.

action_drop_with_warning($msg)
    Drop the part, but add the warning $msg to the e-mail message. If called from filter_multipart, drops all contained parts also.

action_accept_with_warning($msg)
    Accept the part, but add the warning $msg to the e-mail message.

action_replace_with_warning($msg)
    Drop the part and replace it with a text part $msg. If called from filter_multipart, drops all contained parts also.

action_replace_with_url($entity, $doc_root, $base_url, $msg)
    Drop the part, but save it in a unique location under $doc_root. The part is replaced with the text message $msg. The string "_URL_" in $msg is replaced with $base_url/something, which can be used to retrieve the mesage. You should not use this function in filter_multipart. This action is intended for stripping large parts out of the message and replacing them to a link on a Web server. Here's how you would use it in filter():
    $size = (stat($entity->bodyhandle->path))[7];
    if ($size > 1000000) {
    	action_replace_with_url($entity,
    		"/home/httpd/html/mail_parts",
    		"http://mailserver.company.com/mail_parts",
    		"The attachment was larger than 1,000,000 bytes.\n" .
    		"It was removed, but may be accessed at this URL:\n\n" .
    		"\t_URL_\n");
    }
    This example moves attachments greater than 1,000,000 bytes into /home/httpd/html/mail_parts and replaces them with a link. The directory should be accessible via a Web server at http://mailserver.company.com/mail_parts. The generated name is created by performing a SHA1 hash of the part and adding the extension to the ASCII-HEX representation of the hash. If many different e-mails are sent containing an identical large part, only one copy of the part is stored, regardless of the number of senders or recipients. For privacy reasons, you must turn off Web server indexing in the directory in which you place mail parts, or anyone will be able to read them. If indexing is disabled, an attacker would have to guess the SHA1 hash of a part in order to read it.

action_defang($entity, $name, $fname, $type)
    Accept the part, but change its name to $name, its suggested filename to $fname and its MIME type to $type. If $name or $fname are "", then mimedefang.pl generates generic names. Do not use this action in filter_multipart. If you use action_defang, you must define a subroutine called defang_warning in your filter. This routine takes two arguments: $oldfname (the original name of an attachment) and $fname (the defanged version.) It should return a message telling the user what happened. For example:
    sub defang_warning {
        my($oldfname, $fname) = @_;
        return "The attachment '$oldfname' was renamed to '$fname'\n";
    }

action_external_filter($entity, $cmd)
    Run an external UNIX command $cmd. This command must read the part from the file ./FILTERINPUT and leave the result in ./FILTEROUTPUT. If the command executes succesfully, returns 1, otherwise 0. You can test the return value and call another action_ if the filter failed. Do not use this action in filter_multipart.

action_quarantine($entity, $msg)
    Drop the part, but add the warning $msg to the e-mail message. In addition, send a notification to the MIMEDefang administrator and save the part in the quarantine directory on the mail server.

action_quarantine_entire_message($msg)
    Quarantines the entire message in a quarantine directory on the mail server, but does not otherwise affect disposition of the message. Sends a notification to the MIMEDefang administrator that the message was quarantined. If "$msg" is non-empty, a notification is sent to the MIMEDefang administrator.

action_bounce($reply)
    Bounce the entire e-mail message with the one-line error message $reply. This action merely makes a note that the message is to be bounces; remaining parts are still processed. If action_bounce is called for more than one part, the mail is bounced with the message in the final call to action_bounce. You can profitably call action_quarantine followed by action_bounce if you want to keep a copy of the offending part. Note that the message is not bounced immediately; rather, remaining parts are processed and the message is bounced after all parts have been processed. WARNING: action_bounce() is not appropriate for use with viruses, or indeed in any other situation where you have the slightest doubt about the authenticity of the sender's address. Using action_bounce() indiscriminately may result in relaying mail servers sending many annoying error messages to innocent users.

action_tempfail($msg)
    Cause an SMTP "temporary failure" code to be returned, so the sending mail relay requeues the message and tries again later. The message $msg is included with the temporary failure code.

action_discard()
    Silently discard the message, notifying nobody. You can profitably call action_quarantine followed by action_discard if you want to keep a copy of the offending part. Note that the message is not discarded immediately; rather, remaining parts are processed and the message is discarded after all parts have been processed.

action_notify_sender($message)
    This action sends an e-mail back to the original sender with the indicated message. You may call another action after this one. If action_notify_sender is called more than once, the messages are accumulated into a single e-mail message -- at most one notification message is sent per incoming message. The message should be terminated with a newline.

action_notify_administrator($message)
    This action e-mails the MIMEDefang administrator the supplied message. You may call another action after this one; action_notify_administrator does not affect mail processing. If action_notify_administrator is called more than once, the messages are accumulated into a single e-mail message -- at most one notification message is sent per incoming message. The message should be terminated with a newline.

anomy_clean_html($entity, {"name" => val , ...})
    If you have the Anomy mail cleaning tools (http://mailtools.anomy.net) and have installed the Anomy modules in a standard Perl include directory, this function uses an Anomy::HTMLCleaner object to sanitize the HTML code in $entity, which assumed to be of type text/html. The configuration arguments are optional; possible values are documented in comments in the Anomy/HTMLCleaner.pm Perl module.

append_boilerplate($entity, $boilerplate)
    This function is deprecated; see append_text_boilerplate and append_html_boilerplate. This action should only be called from the filter_end routine. It appends the text "$boilerplate" to the first text/plain or text/html part found in the message. If no such part is found, 0 is returned. Otherwise, the function returns 1. Here's an example:
    	sub filter_end {
    		my($entity) = @_;
    		append_boilerplate($entity,
    				   "This e-mail does not represent" .
    				   "the official policy of FuBar, Inc.")
            }

append_text_boilerplate($entity, $boilerplate, $all)
    This action should only be called from filter_end. It appends the text "\n$boilerplate\n" to the first text/plain part (if $all is 0) or to all text/plain parts (if $all is 1).

append_html_boilerplate($entity, $boilerplate, $all)
    This action should only be called from filter_end. It adds the text "\n$boilerplate\n" to the first text/html part (if $all is 0) or to all text/html parts (if $all is 1). This function tries to be smart about inserting the boilerplate; it uses HTML::Parser to detect closing tags and inserts the boilerplate before the </body> tag if there is one, or before the </html> tag if there is no </body>. If there is no </body> or </html> tag, it appends the boilerplate to the end of the part. Do not use append_html_boilerplate unless you have installed the HTML::Parser Perl module. Here is an example illustrating how to use the boilerplate functions:
    	sub filter_end {
    		my($entity) = @_;
    		append_text_boilerplate($entity,
    			"Lame text disclaimer", 0);
    		append_html_boilerplate($entity,
    			"<em>Lame</em> HTML disclaimer", 0);
    	}

action_add_part($entity, $type, $encoding, $data, $fname, $disposition [, $offset])
    This action should only be called from the filter_end routine. It adds a new part to the message, converting the original message to mutipart if necessary. The function returns the part so that additional mime attributes may be set on it. Here's an example:
    	sub filter_end {
    		my($entity) = @_;
    		action_add_part($entity, "text/plain", "-suggest",
     				"This e-mail does not represent" .
    				"the official policy of FuBar, Inc.\n",
    				"disclaimer.txt", "inline");
            }
    $offset is optional; if omitted, it defaults to -1, which adds the new part at the end. See the MIME::Entity man page and the add_part member function for the meaning of $offset.

USEFUL ROUTINES
mimedefang.pl includes some useful functions you can call from your filter:

add_recipient($recip)
    This function adds $recip to the list of envelope recipients. A copy of the message (after any modifications by MIMEDefang) will be sent to $recip in addition to the original recipients.

delete_recipient($recip)
    This function deletes $recip from the list of recipients. That person will not receive a copy of the mail. $recip should exactly match an entry in the @Recipients array for delete_recipient() to work.

resend_message($recip1, $recip2, ...)
    or

resend_message(@recips)
    This function immediately resends the original, unmodified mail message to each of the named recipients. The sender's address is preserved. Be very careful when using this function, because it resends the original message, which may contain undesired attachments. Also, you should not call this function from filter(), because it resends the message each time it is called. This may result in multiple copies being sent if you are not careful. Call from filter_begin() or filter_end() to be safe. The function returns true on success, or false if it fails.

stream_by_domain()
    Do not use this function unless you have Sendmail 8.12 and locally- submitted e-mail is submitted using SMTP. This function should only be called at the very beginning of filter_begin(), like this:
    	sub filter_begin {
    		if (stream_by_domain()) {
    			return;
    		}
    		# Rest of filter_begin
    	}
    stream_by_domain() looks at all the recipients of the message, and if they belong to the same domain (e.g., joe@domain.com, jane@domain.com and sue@domain.com), it returns 0 and sets the global variable $Domain to the domain (domain.com in this example.) If users are in different domains, stream_by_domain() resends the message (once to each domain) and returns 1 For example, if the original recipients are joe@abc.net, jane@xyz.net and sue@abc.net, the original message is resent twice: One copy to joe@abc.net and sue@abc.net, and another copy to jane@xyz.net. Also, any subsequent scanning is cancelled (filter() and filter_end() will not be called for the original message) and the message is silently discarded. If you have Sendmail 8.12, then locally-submitted messages are sent via SMTP, and MIMEDefang will be called for each resent message. It is possible to set up Sendmail 8.12 so locally-submitted messages are delivered directly; in this case, stream_by_domain will not work. Using stream_by_domain allows you to customize your filter rules for each domain. If you use the function as described above, you can do this in your filter routine:
    	sub filter {
    		my($entity, $fname, $ext, $type) = @_;
    		if ($Domain eq "abc.com") {
    			# Filter actions for abc.com
    		} elsif ($Domain eq "xyz.com") {
    			# Filter actions for xyz.com
    		} else {
    			# Default filter actions
    		}
    	}
    You cannot rely on $Domain being set unless you have called stream_by_domain().

stream_by_recipient()
    Do not use this function unless you have Sendmail 8.12 and locally- submitted e-mail is submitted using SMTP. This function should only be called at the very beginning of filter_begin(), like this:
    	sub filter_begin {
    		if (stream_by_recipient()) {
    			return;
    		}
    		# Rest of filter_begin
    	}
    If there is more than one recipient, stream_by_recipient() resends the message once to each recipient. That way, you can customize your filter rules on a per-recipient basis. This may increase the load on your mail server considerably. Also, a "recipient" is determined before alias expansion. So "all@mydomain.com" is considered a single recipient, even if Sendmail delivers to a list. If you have Sendmail 8.12, then locally-submitted messages are sent via SMTP, and MIMEDefang will be called for each resent message. It is possible to set up Sendmail 8.12 so locally-submitted messages are delivered directly; in this case, stream_by_recipient() will not work. stream_by_recipient() allows you to customize your filter rules for each recipient in a manner similar to stream_by_domain().

TEST FUNCTIONS
mimedefang.pl includes some "test" functions:

relay_is_blacklisted($relay, $domain)
    This checks an ORBS-type real-time spam blacklist, and returns true if the relay host is blacklisted, or false otherwise. For example, you could use this:
    	if (relay_is_blacklisted($RelayAddr, "inputs.orbs.org")) {
    		action_add_header("X-Blacklist-Warning",
    				  "Relay $RelayAddr is blacklisted by ORBS");
    	}

message_rejected()
    Returns true if any of action_tempfail, action_bounce or action_discard have been called for this message; returns false otherwise.

If you have the Mail::SpamAssassin perl module installed (see http://www.spamassassin.org) you may call any of the spam_assassin_* functions. They should only be called from filter_begin as they operate on the entire message at once. Most functions use an optionally provided config file. If no config file is provided, mimedefang.pl will look for one of three default SpamAssassin preference files. The first of the following found will be used:

o   /usr/local/etc/mimedefang/spamassassin/sa-mimedefang.cf

o   /usr/local/etc/mimedefang/spamassassin/local.cf

o   /usr/local/etc/mimedefang/spamassassin.cf

spam_assassin_is_spam([ $config_file ])
    Determine if the current message is SPAM/UCE as determined by SpamAssassin. Compares the score of the message against the threshold score (see below) and returns true if it is. Uses spam_assassin_check below.

spam_assassin_check([ $config_file ])
    This function returns a four-element list of the form ($hits, $required, $tests, $report). $hits is the "score" given to the message by SpamAssassin (higher score means more likely SPAM). $required is the number of hits required before SpamAssassin concludes that the message is SPAM. $tests is a comma-separated list of SpamAssassin test names, and $report is text detailing which tests triggered and their point score. This gives you insight into why SpamAssassin concluded that the message is SPAM. Uses spam_assassin_status below.

spam_assassin_status([ $config_file ])
    This function returns a Mail::SpamAssasin::PerMsgStatus object. Read the SpamAssassin documentation for details about this object. You are responsible for calling the finish method when you are done with it. Uses spam_assassin_init and spam_assassin_mail below.

spam_assassin_init([ $config_file ])
    This function returns the new global Mail::SpamAssassin object with the specified or default config (outlined above). If the global object is already defined, returns it -- does not change config files! The object can be used to perform other SpamAssassin related functions.

spam_assassin_mail()
    This function returns a Mail::SpamAssassin::NoMailAudit object with the current email message contained in it. It may be used to perform other SpamAssassin related functions.

message_contains_virus_rav()

message_contains_virus_trend()

message_contains_virus_nai()

message_contains_virus_fsav()

message_contains_virus_hbedv()

message_contains_virus_sophos()

message_contains_virus_avp()

message_contains_virus_filescan()

message_contains_virus_fprot()
    These functions should be called in list context. They use the indicated anti-virus software to scan the message for viruses. These functions are intended for use in filter_begin() to make an initial scan of the e-mail message. The supported virus scanners are:

rav Reliable AntiVirus - http://www.ravantivirus.com/

nai NAI "uvscan" - http://www.nai.com/

fsav
    F-Secure Anti-Virus - http://www.f-secure.com/

hbedv
    H+BEDV "AntiVir" - http://www.hbedv.com/

sophos
    Sophos AntiVirus - http://www.sophos.com/

avp Kaspersky AVP - http://www.avp.ru/

f-prot
    F-RISK F-PROT - http://www.f-prot.com/ The return value is a three-element list: ($code, $category, $action). $code is the actual return code from the virus scanner. $category is a string categorizing the return code: "ok" - no viruses detected. "not-installed" - indicated virus scanner is not installed. "cannot-execute" - for some reason, the scanner could not be executed. "virus" - a virus was found. "suspicious" - a "suspicious" file was found. "interrupted" - scanning was interrupted. "swerr" - an internal scanner software error occurred. $action is a string containing the recommended action: "ok" - allow the message through unmolested. "quarantine" - a virus was detected; quarantine it. "tempfail" - something went wrong; tempfail the message.

message_contains_virus_openantivirus([$host])
    Connects to the specified host:port (default $OpenAVHost), where the OpenAntiVirus daemon is expected to be listening. Return values are the same as the other message_contains_virus functions.

message_contains_virus_sophie([$sophie_sock])
    Connects to the specified socket (default $SophieSock), where the Sophie daemon is expected to be listening. Return values are the same as the other message_contains_virus functions.

entity_contains_virus_rav($entity)

entity_contains_virus_trend($entity)

entity_contains_virus_nai($entity)

entity_contains_virus_fsav($entity)

entity_contains_virus_hbedv($entity)

entity_contains_virus_sophos($entity)

entity_contains_virus_avp($entity)

entity_contains_virus_filescan($entity)

entity_contains_virus_fprot($entity)
    These functions, meant to be called from filter(), are similar to the message_contains_virus functions except they scan only the current part. They should be called from list context, and their return values are as described for the message_contains_virus functions.

entity_contains_virus_openantivirus($entity[, $host])
    Connects to the specified host:port (default $OpenAVHost), where the OpenAntiVirus daemon is expected to be listening. Return values are the same as the other entity_contains_virus functions.

entity_contains_virus_sophie($entity[, $sophie_sock])
    Connects to the specified socket (default $SophieSock), where the Sophie daemon is expected to be listening. Return values are the same as the other entity_contains_virus functions.

SUPPORTED VIRUS SCANNERS
The following virus scanners are supported by MIMEDefang:

o   OpenAntiVirus (http://www.openantivirus.org/) is supported in daemon-scanning mode. This is the recommended tool to use with MIMEDefang.

o   Reliable AntiVirus (http://www.ravantivirus.com/)

o   Trend Micro vscan (http://www.antivirus.com/)

o   Sophos Sweep (http://www.sophos.com/products/antivirus/savunix.html)

o   H+BEDV AntiVir (http://www.hbedv.com/)

o   NAI uvscan (http://www.nai.com)

o   F-Secure fsav (http://www.f-secure.com)

o   Kaspersky Anti-Virus (AVP) (http://www.kaspersky.com/)

o   F-Risk F-Prot (http://www.fprot.com/)

o   The File::Scan Perl module (http://freshmeat.net/projects/filescan/)

o   Sophie (http://www.vanja.com/tools/sophie/), which uses the libsavi library from Sophos, is supported in daemon-scanning mode.

AUTHORS
mimedefang was written by David F. Skoll <dfs@roaringpenguin.com>. The mimedefang home page is http://www.roaringpenguin.com/mimedefang/.

SEE ALSO
mimedefang(8), mimedefang.pl(8)