Mailman delivers all mail posted from a particular mail server

Overview

When operating a mailing list with Mailman, you may want to accept and deliver all emails sent from within your organization. For example, if you are using Mailman as a contact point for your organization. This article describes how to extend Mailman's moderator decision module to accept and deliver all emails posted from a particular mail server.

background

To receive mail from non-mailing list participants when running a mailing list with Mailman, either (1) set the generic_nonmember_action option to "Approve" or (2) set the accept_these_nonmembers option to an appropriate regular expression. There are options such as. However, the former (1) accepts all emails, and the latter (2) also relies on headers that are easy to spoof, making it vulnerable to spam.

In this article,

  1. The outgoing mail server used by the members of your organization is fixed.
  2. Any mail server on the route from the outgoing mail server to Mailman can be trusted.

Based on the premise, we will introduce the setting to deliver all the mail posted from the sending mail server based on the contents of the Received header.

Setting Example

Place code similar to the following as /usr/lib/mailman/Mailman/Handlers/TrustedServerModerate.py. Please read the path / usr / lib / mailman / as appropriate according to your environment.

TrustedServerModerate.py


# Copyright (C) 2015 by TSUCHIYA Masatoshi <[email protected]>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.

"""This module implements server based moderation.  If a user used one
of trusted remote servers to send his/her message, and only if it has
been delivered through trusted local servers, it is approved as a
trusted message.  Otherwise, it will be handled by the default rule of
Mailman.

USAGE:

Add following codes to mm_cfg.py:

TRUSTEDLOCALSERVER = [ "127.0.0.1",
                       "^192\.168\.10\." ]

TRUSTEDREMOTESERVER = [ "192.168.10.1" ]

GLOBAL_PIPELINE[GLOBAL_PIPELINE.index('Moderate')] = 'TrustedServerModerate'

"""

import re
from Mailman import mm_cfg
from Mailman.Handlers.Moderate import process as moderate_process
from Mailman.Logging.Syslog import syslog

def process(mlist, msg, msgdata):
    def extract_ipaddr(str):
        m = re.search('\[(\d+\.\d+\.\d+\.\d+)\]', str)
        if m:
            return m.group(1)
        m = re.search('\[((?:[a-fA-F0-9]{4}:+)+[a-fA-F0-9]{4})\]', str)
        if m:
            return m.group(1)
        if '[IPv6:::1]'in str:
            return '127.0.0.1'
        else:
            return ''

    def matches_p(ipaddr, patterns):
        for pat in patterns:
            if pat.startswith('^'):
                if re.match(pat, ipaddr):
                    return 1
            else:
                if pat==ipaddr:
                    return 1
        return 0

    def trusted_message_p(message):
        received=[extract_ipaddr(x) for x in message.get_all('Received') if re.match("^from", x)]
        syslog('error', 'Servers which deliver this message are %s', ' / '.join(received))
        received.reverse()
        try:
            while received and matches_p(received[-1], mm_cfg.TRUSTEDLOCALSERVER):
                received.pop()
            remote=0
            while received and matches_p(received[-1], mm_cfg.TRUSTEDREMOTESERVER):
                received.pop()
                remote+=1
            if remote > 0:
                if len(received) <= 1:
                    syslog('error', 'This message is trusted')
                    return 1
                else:
                    return 0
            else:
                return 0
        except AttributeError:
            return 0

    if mlist.generic_nonmember_action == 1 and trusted_message_p(msg):
        return
    return moderate_process(mlist, msg, msgdata)

Then, write the following three specifications in /etc/mailman/mm_cfg.py. First, specify the IP address of the outgoing mail server used by the members as follows.

TRUSTEDREMOTESERVER = [ "192.168.10.1",
                        "192.168.10.2" ]

In addition, in the settings of this article, whether or not to deliver mail is determined based on the via information of the sending mail server specified here. Therefore, the outgoing mail server needs to accept only the mail authenticated by the method such as SMTP AUTH.

Second, specify the IP address of a known and trusted mail server from the outgoing mail server to reach Mailman as follows:

TRUSTEDLOCALSERVER = [ "127.0.0.1",
                       "192.168.10.3",
                       "192.168.10.4",
                       "192.168.10.5" ]

Note that a known and trusted mail server must include the IP address of the server on which Mailman is running.

If there is a ^ at the beginning of the string, it will be interpreted as a regular expression, so the above specification is equivalent to the following specification.

TRUSTEDREMOTESERVER = [ "^192\.168\.10\.[12]$" ]
TRUSTEDLOCALSERVER  = [ "127.0.0.1", "^192\.168\.10\.[345]$" ]

Third, specify to use the above module instead of the Mailman / Handlers / Moderate.py that comes with Mailman itself.

GLOBAL_PIPELINE[GLOBAL_PIPELINE.index('Moderate')] = 'TrustedServerModerate'

Commentary

In the above setting example, emails posted by the following routes will be accepted and delivered.

MUA
 ↓
Outgoing mail server(192.168.10.1 or 2)
 ↓
Relay mail server(192.168.10.3 or 4)
 ↓
Mailman server(192.168.10.5)

On the other hand, in the case of the following route, it will not be delivered because the user authentication by the sending mail server has not been performed.

MUA
 ↓
Unknown mail server
 ↓
Outgoing mail server(192.168.10.1 or 2)
 ↓
Relay mail server(192.168.10.3 or 4)
 ↓
Mailman server(192.168.10.5)

Also, the following routes will not be delivered because the Received header may be forged.

MUA
 ↓
Outgoing mail server(192.168.10.1 or 2)
 ↓
Unknown mail server
 ↓
Relay mail server(192.168.10.3 or 4)
 ↓
Mailman server(192.168.10.5)

That is, the sending mail server, the relay mail server, and the Mailman server are under the control of the own organization, and the route information is extracted on the assumption that the Received header added by the mail server is reliable, and the sending mail server is used. It is set to deliver only the mail authenticated by the user.

Recommended Posts

Mailman delivers all mail posted from a particular mail server
Mailman delivers all DKIM-signed emails posted from specific domains
Set up a mail server using Twisted
Send a message from Slack to a Python server
Create an account from CentOS mail server construction