[Mimedefang] Future development

Richard Laager rlaager at wiktel.com
Sun Nov 22 16:21:39 EST 2020

On 11/22/20 12:32 PM, Dianne Skoll via MIMEDefang wrote:
> mimedefang.pl is over 7500 lines of
> Perl in one ugly file with a ton of global variables.  It needs a major
> overhaul.  I would start by writing a MD::Filter base class
> and storing state in the MD::Filter object.  Callbacks could be implemented
> as methods and users could subclass MD::Filter to implement their behaviour.

Storing state in objects instead of global variables seems better.

The current design is inconsistent between filter_*(). For example,
filter_sender() gets arguments of $sender, $ip, $hostname, and $helo,
but in filter_begin()/filter_end(), one has to use globals of $Sender,
$RelayAddr, $$RelayHostname, and $Helo. Improving that would be nice,
and moving to objects seems like one way to do that. (Yes, I know those
globals are available in filter_sender() and that's what I use.)

Likewise, the early functions return the filter decision:
    return ('REJECT', "Go away");
while the later functions use action_*() calls:
    action_bounce("Go away");

This would be relatively easy to change, keeping the old way for
compatibility for a while. The biggest question is which way to
harmonize it: the return approach seems to conceptually fit the idea of
"I've decided what to do, so I'm done." but perhaps the fact that
action_*() allow you to flag the action and then continue with
additional processing/cleanup is valuable to someone. FWIW, I
immediately return after all my action_*() calls.

nit: action_bounce() should probably be called action_reject(). That'd
be easy to change now, keeping the old one for compatibility.

I have a few local changes that might be more broadly applicable:

I have an inlined version of md_graphdefang_log(). Some of the changes
are not likely to be useful upstream, but one that is worth considering
is lifting the in_message_context requirement. This will result in
certain fields (e.g. subject) being empty for logs from the early filter
functions (filter_relay, filter_sender, and filter_recipient). That's
unavoidable and isn't a problem. But it makes it possible to _use_ the
logging function in those contexts. (Note: I don't actually use
graphdefang itself.)

I have a version of resend_message_specifying_mode() that allows adding
headers to the resent message.

I defer loading SpamAssassin until spam_assassin_init(). By waiting, we
reduce the memory consumption of workers that never call SpamAssassin
(e.g. workers that happen to only handle filter_sender and
filter_recipient checks).

My local spam_assassin_mail() (which inlines
synthesize_received_header()) adds " (authenticated bits=0)" to the end
of the Received header if it's a "local" relay (i.e. the relay is in my
list of allowed IP ranges and/or has authenticated). This avoids
SpamAssassin penalizing mail as "direct to MX". I'd suggest taking a
parameter to spam_assassin_mail() which would need to be passed to
synthesize_received_header() that specifies whether the user is local.
If the parameter's value is undef (which would be the default), look at
$SendmailMacros{"auth_authen"}. This would give sane "out of the box"
behavior while still allowing the filter to forcibly override it to true
(i.e. to allow for checking the IP range) or false (for whatever reason).

I also add a "To: undisclosed-recipients:;" header. 1) I have no notes
as to why I am doing that. I don't know if that was old mimedefang
behavior that has since been removed. 2) I have no idea what is up with
the colon and/or semi-colon at the end of that line.


More information about the MIMEDefang mailing list