Manpage logo

Mailmunge::Filter::Compat - base class for Mailmunge filtering that includes some backward-compatibility for migrating MIMEDefang filter code.

NAME  SYNOPSIS  OPERATION  ABSTRACT  THINGS YOU SHOULD NEVER DO IN YOUR FILTER CODE  METHODS  filter_message($ctx)  filter_begin($ctx)  filter_multipart($ctx, $part, $fname, $extension, $type)  filter($ctx, $part, $fname, $extension, $type)  filter_end($ctx)  action_accept($ctx [, $warning])  action_drop($ctx [, $warning])  action_drop_with_warning($ctx, $warning)  action_accept_with_warning($ctx, $warning)  action_replace_with_warning($ctx, $warning)  action_add_entity($ctx, $entity [, $offset])  action_add_part($ctx, $type, $encoding, $data, $fname, $disposition,$offset)  take_stab_at_filename($entity)  CONVERTING FROM MIMEDefang  The Filter  Callbacks  Return Values  Global Variables  VARIOUS BITS OF MIMEDEFANG FUNCTIONALITY  AUTHOR  LICENSE 

NAME

Mailmunge::Filter::Compat − base class for Mailmunge filtering that includes some backward−compatibility for migrating MIMEDefang filter code.

SYNOPSIS

"Mailmunge::Filter::Compat" is a subclass of "Mailmunge::Filter". As such, all methods documented in Mailmunge::Filter are also available here.

"Mailmunge::Filter::Compat" implements a "filter_message" function that in turn calls "filter_begin", "filter", "filter_multipart", "filter_end" and "filter_wrapup" methods. These methods operate similarly to their counterparts in MIMEDefang filtering code and make it easier to migrate MIMEDefang filters to Mailmunge.

The return values from "filter_begin", "filter", "filter_multipart", "filter_end" and "filter_wrapup" are normally ignored. However, if any of these functions returns a Mailmunge::Response object, then it is interpreted the same way as a "Mailmunge::Response" object returned by "filter_message".

If you derive your filter from "Mailmunge::Filter::Compat", you must not override "filter_message". Instead, override "filter_begin", "filter", "filter_multipart", "filter_end" and "filter_wrapup" as required.

Any functions that are callable from "filter_message" as well as Mailmunge::Context methods available to "filter_message" are available in "filter_begin", "filter", "flter_multipart" and "filter_end".

OPERATION

The body filtering functions are called as follows:

1.

"filter_begin" is called once.

2.

Recursing through the MIME::Entity object "$ctx−>mime_entity", "filter_multipart" is called for each multipart/* sub−part and "filter" is called for each non−multipart sub−part.

3.

"filter_end" is called once. This is the last point at which you are allowed to modify the message body.

4.

"filter_wrapup" is called once. In "filter_wrapup", modifications to the message body are not allowed, but you are allowed to modify top−level headers. Typically, this is where you would do DKIM−signing.

Note that if any method rejects a message by calling "action_bounce", "action_discard" or "action_tempfail", then filtering is short−circuited and remaining callbacks are not called.

ABSTRACT

package MyFilter;
use base qw(Mailmunge::Filter::Compat);
sub filter_begin {
my ($self, $ctx) = @_;
# ... etc
}

THINGS YOU SHOULD NEVER DO IN YOUR FILTER CODE

Because Mailmunge filters use STDIN and STDOUT to communicate with the multiplexor, you should never read from STDIN or write to STDOUT from filter code you write. It's OK to write to STDERR, however; if "mailmunge−multiplexor" was invoked with the "−l" option, then anything your filter prints to STDERR will be logged in the mail log.

METHODS

filter_message($ctx)

Overrides "filter_message" from the base "Mailmunge::Filter" class. Do not tamper with or override this method.

The $ctx fields available are documented in Mailmunge::Filter's "filter_message" documentation; these same fields are available in "filter_begin", "filter_multipart", "filter", "filter_end" and "filter_wrapup".

filter_begin($ctx)

Called once at the beginning of filtering. See "filter_message" in Mailmunge::Filter for the list of $ctx fields available.

filter_multipart($ctx, $part, $fname, $extension, $type)

filter_multipart is called once for each "multipart/*" part in the message. $part is the sub−part being filtered and is a MIME::Entity. $fname is the best−guess at the filename associated with the part (if any); it is taken from the Content−Type.name or Content−Disposition.filename MIME fields. $ext is the filename extension including the leading dot associated with $fname, and $type is the MIME type of the part.

filter($ctx, $part, $fname, $extension, $type)

filter is called once for each non−multipart part in the message. The arguments are the same as "filter_multipart".

filter_end($ctx)

filter_end is called once at the end of filtering. This is the last place you can modify the message (which you can do with "action_add_entity" or "action_add_part").

action_accept($ctx [, $warning])

This method may only be called in "filter" or "filter_multipart". It causes the part to remain in the message. If no method that removes or modifies a part is called, then "action_accept" is implicitly the default.

If $warning is supplied, then we call "action_accept_with_warning" to add a warning message in a new "text/plain" part appended to the message.

action_drop($ctx [, $warning])

This method may only be called in "filter" or "filter_multipart". It causes the part (and if multipart, all sub−parts) to be silently removed from the message. However, if $warning is supplied, then we call "action_drop_with_warning" instead.

action_drop_with_warning($ctx, $warning)

This method may only be called in "filter" or "filter_multipart". It causes the part (and if multipart, all sub−parts) to be removed from the message. Additionally, a warning message is added in a new "text/plain" part that is appended to the message.

action_accept_with_warning($ctx, $warning)

This method may only be called in "filter" or "filter_multipart". It causes a warning message to be added in a new "text/plain" part that is appended to the message.

action_replace_with_warning($ctx, $warning)

This method may only be called in "filter" or "filter_multipart". It causes the part to be removed from the message and replaced with a new "text/plain" part containing the $warning message.

action_add_entity($ctx, $entity [, $offset])

Causes a new "MIME::Entity" to be added to the message at offset $offset, which is the zero−based index in the top−level message at which to add the entity. If $offset is not supplied, the part is added to the end of the message.

action_add_part($ctx, $type, $encoding, $data, $fname, $disposition,$offset)

Creates a new "MIME::Entity" whose MIME type is $type, Content−Encoding is $encoding, Content−Disposition is $disposition, Content−Disposition.filename is $fname and contents are $data. Then calls action_add_entity with the new part and supplied $offset. This is really just a convenience function that builds the MIME::Entity for you.

take_stab_at_filename($entity)

Returns Mailmunge's best−guess at the filename associated with MIME::Entity $entity. Note that the decoded filename is returned, so any MIME encoding is parsed and decoded.

CONVERTING FROM MIMEDefang

Conversion of a filter from MIMEDefang to Mailmunge can range from very mechanical to quite complicated, depending on the filter. This section is a MIMEDefang−to−Mailmunge conversion guide.

The Filter

A MIMEDefang filter is a fragment of a Perl program, whereas a Mailmunge filter is a complete Perl program.

To convert a MIMEDefang filter to Mailmunge, your Mailmunge filter should start something like this:

package MyFilter;
use strict;
use warnings;
use base qw(Mailmunge::Filter::Compat);
my $filter = MyFilter−>new();
$filter−>run();

Callbacks

Mailmunge callbacks are similar to MIMEDefang, but have different arguments. The Following table shows the correspondence.

MIMEDefang Mailmunge
========== =========
sub filter_initialize { sub initialize {
# ... my ($self) = @_;
} # ...
}
sub filter_cleanup { sub cleanup {
# ... my ($self) = @_;
} # ...
}
sub filter_relay { sub filter_relay {
my ($ip, $name, $port, my ($self, $ctx) = @_;
$my_ip, $my_port, $qid) = @_; # ...
# ... }
}
sub filter_helo { sub filter_helo {
my ($ip, $name, $helo, $port, my ($self, $ctx) = @_;
$my_ip, $my_port, $qid) = @_; # ...
# ... }
}
sub filter_sender { sub filter_sender {
my ($sender, $ip, $name, $helo) = @_; my ($self, $ctx) = @_;
# ... # ...
} }
sub filter_recipient { sub filter_recipient {
my ($recip, $sender, $ip, $name, my ($self, $ctx) = @_;
$first_recip, $helo, # ...
$mailer, $host, $addr) = @_; }
# ...
}
sub filter_begin { sub filter_begin {
my ($entity) = @_; my ($self, $ctx) = @_;
# ... # ... Entity is $ctx−>mime_entity
} }
sub filter { sub filter {
my ($entity, $fname, my ($self, $ctx, $entity, $fname,
$extension, $mime_type) = @_; $extension, $mime_type) = @_;
# ... # ...
} }
sub filter_multipart { sub filter_multipart {
my ($entity, $fname, my ($self, $ctx, $entity, $fname,
$extension, $mime_type) = @_; $extension, $mime_type) = @_;
# ... # ...
} }
sub filter_end { sub filter_end {
my ($entity) = @_; my ($self, $ctx) = @_;
# ... # ... Entity is $ctx−>mime_entity
} }
sub filter_wrapup { sub filter_wrapup {
my ($entity) = @_; my ($self, $ctx) = @_;
# ... # ... Entity is $ctx−>mime_entity
} }
sub filter_map { sub filter_map {
my ($map, $key) = @_; my ($self, $map, $key) = @_;
# ... # ...
} }
sub filter_tick { sub tick {
my ($tick_no) = @_; my ($self, $tick_no) = @_;
# ... # ...
} }
sub filter_validate { ... } No equivalent in Mailmunge
sub defang_warning { ... } No equivalent in Mailmunge

Return Values

Many MIMEDefang functions return an array of elements. In Mailmunge, they instead return a Mailmunge::Response object.

MIMEDefang Mailmunge
========== =========
return ('CONTINUE', 'ok'); return Mailmunge::Response−>CONTINUE();
return ('TEMPFAIL', 'Message', 421, '4.1.1'); return Mailmunge::Response−>TEMPFAIL(message => 'Message', code => 421, dsn => '4.1.1');
return ('TEMPFAIL', 'Message', 571, '5.2.1'); return Mailmunge::Response−>REJECT(message => 'Message', code => 571, dsn => '5.2.1');
return ('DISCARD', 'Message'); return Mailmunge::Response−>DISCARD(message => 'Message');
return ('ACCEPT_AND_NO_MORE_FILTERING', 'ok'); return Mailmunge::Response−>ACCEPT_AND_NO_MORE_FILTERING();

Global Variables

MIMEDefang filters make use of a plethora of global variables. Mailmunge does not use any global variables. The correspondences for the most important variables are shown below.

MIMEDefang Mailmunge
========== =========
$MessageID $ctx−>message_id
$RealRelayAddr $ctx−>connecting_ip
$RealRelayHostname $ctx−>connecting_name
$CWD $ctx−>cwd
@ESMTPArgs @{$ctx−>esmtp_args}
@SenderESMTPArgs @{$ctx−>esmtp_args}
$Helo $ctx−>helo
$RelayAddr $ctx−>hostip
$RelayHostname $ctx−>hostname
$MIMEDefangID $ctx−>mailmunge_id
$MessageID $ctx−>message_id
$QueueID $ctx−>qid
%RecipientESMTPArgs %{$ctx−>recipient_esmtp_args}
@Recipients @{$ctx−>recipients}
$Sender $ctx−>sender
$Subject $ctx−>subject
$SubjectCount $ctx−>subject_count
$SuspiciousCharsInHeaders $ctx−>suspicious_chars_in_headers
$SuspiciousCharsInBody $ctx−>suspicious_chars_in_body
$WasResent $ctx−>was_resent

VARIOUS BITS OF MIMEDEFANG FUNCTIONALITY

Mailmunge moves a lot of functionality out of the core filter into modules. Here is a rough correspondence between MIMEDefang and Mailmunge functionality. Note that in some cases, we recommend external CPAN modules that already have the required functionality; duplicating that effort within Mailmunge would not be efficient.
DNSBL lookups

Instead of the various "relay_is_blacklisted" functions, use Net::DNSBL::Client <https://metacpan.org/pod/Net::DNSBL::Client>.

Streaming

Instead of "stream_by_recipient" or "stream_by_domain", use Mailmunge::Action::Stream.

Virus−Scanning

Instead of all the "*_contains_virus_*" functions, use File::VirusScan <https://metacpan.org/pod/File::VirusScan>.

Bogus MX Host Checks

Instead of "md_get_bogus_mx_hosts", use Mailmunge::Test::GetMX.

Boilerplate

Instead of "append_text_boilerplate" or "append_html_boilerplate", use Mailmunge::Action::Boilerplate.

SpamAssassin

Instead of the various "spam_assassin_*" functions, use Mailmunge::Test::SpamAssassin.

Rspamd

Instead of "rspamd_check", use Mailmunge::Test::Rspamd.

SMTP Call−forwards

Instead of "md_check_against_smtp_server", use Mailmunge::Test::SMTPForward.

AUTHOR

Dianne Skoll <[email protected]>

LICENSE

This code is licensed under the terms of the GNU General Public License, version 2.


Updated 2026-06-01 - jenkler.se | uex.se