Sam Trenholme's webpage
Support this website

Postfix + Mailman in CentOS 6

 

March 23 2014

This blog describes how I have configured Postfix to work in CentOS 6 to receive email, and how I set up Mailman. It includes information on getting Nginx to display Mailman's web interface.

==Mail transport agent==

A mail transport agent (MTA) is a program that sends and receives email.

There are a number of mail transport agents out there: Smail (last updated 2005), Qmail (last updated 1998), netqmail (last updated 2005), Courier (currently maintained), Exim (currently maintained), Sendmail (CentOS package available), and Postfix (CentOS package available).

I chose Postfix becuase

  • It is included with CentOS. This saves me from the bother of having a package which I have to track security updates for.

  • It is more streamlined than Sendmail, the other MTA included with Postfix

==Installing Postfix==

As root:

yum -y install postfix
chkconfig --levels 2345 postfix on
service postfix start

==After installing Postfix==

After installing Postfix, I edited /etc/postfix/main.cf

  • inet_interfaces = server.example.com, localhost

  • inet_protocols = ipv4

  • mydestination = $myhostname, localhost.$mydomain, localhost, example.com, server.example.com

  • recipient_delimiter = -

The reason I changed the recipient_delimiter is because a lot of web sites out there will not accept an email address with a + in it, but have no problem with email addresses with a '-'.

Change server.example.com in to the name of the machine running the Postfix server.

Note that it is not possible to run a SMTP server on most home internet conections without complicated configurations, since ISPs have had to block outgoing SMTP because of spam abuse.

==Adding an alias==

An alias is another name for a given email address. For example, to allow mail sent to foo@example.com to be delivered to bar's account, edit /etc/aliases, adding the following line:

foo: bar

Next, do this as root:

newaliases

Now, all mail sent to foo@example.com will be forwarded to bar@example.com

==Adding an alias that uses delimiter==

To add an alias with virtual address support (foo-anything@example.com is delivered to foo@example.com), it's necessary to set up a virtual host. Here is what /etc/postfix/virtual looks like:

foo@example.com bar

Once that is set up, do this as root:

postmap /etc/postfix/virtual

Make sure virtual support is in the main.cf file. The lines look like this:

virtual_maps = hash:/etc/postfix/virtual
virtual_mailbox_base = /var/mail

==Don't be a spammer!==

Now that basic email works, the next step was to install mailman, a mailing list manager, in my VPS.

First of all, before installing mailman, make sure your hosting provider's AUP allows mailing lists. Since I use inexpensive $15/year nodes, not all of them allow mailing lists.

It is best to use an ISP whose AUP explicitly allows mailing list software to be run. For example, while I am very happy with the service I have gotten with my node on Crissic, it is not a node for running any kind of mailing list. Even though Crissic's AUP allows me to send 400 emails a day (less than the amount of traffic my one list generates), their spam filters stopped me from sending any and all email after I sent only 136 mails.

Their support department explained to me that the issue was that Mailman sends too many emails at once, which triggers their spam filters. The way to not trigger those filters is to rate limit outgoing email. Unfortunately, neither Postfix nor Mailman appear to have a global sending rate limit. While Postfix can rate limit how mach a single email or mail server gets email via destination_concurrency_limit, destination_rate_delay, and extra_recipient_limit, Postfix needs a third party module like Policyd to have a global quota.

BuyVM, on the other hand, allows me to run a mailing list, but their AUP requires me to get permission via a support ticket first. After opening up a ticket asking to run my low-traffic mailing list, I almost immediately got a reply approving the request (even though I sent the request late Saturday night).

It's very important to make sure anyone and everyone on your mailing list has opted in to the mailing list. This means: They sent an email to the mailing list manager which then subscribed them; they gave explicit consent to receive email from the list.

==Installing mailman==

There is one, and only one mailing list package included with CentOS: Mailman. The issue is, since I use Nginx and Postfix, installing mailman is somewhat difficult. Partial instructions are here:

http://black-pixel.net/mailman-with-postfix-and-nginx-on-centos-6.html
I will recap those instructions, filling in holes as needed.

==fcgiwrap for CentOS 6==

That page does not include instructions on giving CentOS 6 fastcgi cgi-bin support (fcgiwrap), so I have forked fcgiwrap to port it to CentOS 6:

https://github.com/samboy/fcgiwrap
To install that package, as root:

yum -y install git

Follow this by, as non-root (user):

git clone https://github.com/samboy/fcgiwrap

Read the README file in the fcgiwrap directory for instructions on compiling and installing fcgiwrap in CentOS 6. Unlike other packages, EPEL is not needed to use fcgiwrap.

==postfix-to-mailman.py for CentOS 6==

In addition, here is postfix-to-mailman.py for CentOS 6:

http://samiam.org/software/postfix-to-mailman-centos.py
But, as it turns out, my particular mailman setup doesn't use it (I just edit aliases by hand to add a new mailinst list), so this script has not been fully tested, but starts up.

==Nginx and mailman==

Here are the relevant lines from my Nginx configuration:

    # Mailman mailing list web interface
    server {
        listen       [::]:80;
        listen       [::]:443 ssl;
        ssl_certificate /usr/local/nginx/server.crt;
        ssl_certificate_key /usr/local/nginx/server.key;
        server_name  mailman.example.com;
        location / {
            root   html/;
            index  index.html index.htm index.php;
        }
        location ~ \.php$ {
            root           html/samiam.org/;
            fastcgi_pass   unix:/tmp/php.socket;
            fastcgi_index  index.php;
            include        fastcgi_params;
        }
        location /mailman/cgi-bin {
                root /usr/lib;
                fastcgi_split_path_info (^/mailman/cgi-bin/[^/]*)(.*)$;
                include /usr/local/nginx/conf/fastcgi_params;
          fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                fastcgi_param PATH_INFO $fastcgi_path_info;
            fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
                fastcgi_intercept_errors on;
                fastcgi_pass   unix:/var/run/fcgiwrap.socket;
        }
        location /icons {
                alias /usr/lib/mailman/icons/;
        }
        location /images/mailman {
                alias /usr/lib/mailman/icons/;
        }
        location /pipermail {
                alias /var/lib/mailman/archives/public;
                autoindex on;
        }
    }

Note two different values for fastcgi_pass. The PHP scripts are passed to a fastcgi socket started using this code (run as "nobody"):

#!/bin/bash
if id | grep root > /dev/null ; then
        echo Do not run this as root
        exit
fi
BIND=/tmp/php.socket
USER=nobody
PHP_CGI=/usr/bin/php-cgi
export USER=nobody
export PATH=/usr/bin
nohup php-cgi -b $BIND &

The mailman CGI scripts are passed to fcgiwrap; its installation is described above.

==Configuring Postfix for Mailman==

Postfix doesn't need a lot of configuration for Mailman, as long as new lists are being generated from the command line.

It's important to edit /usr/lib/mailman/Mailman/Defaults.py to have lines that look like this:

DEFAULT_EMAIL_HOST = 'mailman.example.com'
DEFAULT_URL_HOST = 'mailman.example.com'
DEFAULT_URL_PATTERN = 'https://%s/mailman/cgi-bin/'

And edit /usr/lib/mailman/Mailman/mm_cfg.py to have lines like this:

DEFAULT_URL_HOST   = 'mailman.example.com'
DEFAULT_EMAIL_HOST = 'mailman.example.com'

This should be done before making any mailing lists for Mailman.

==Make a new list in Mailman==

cd /usr/lib/mailman/bin
su
./newlist

It will ask you the name of the list, the email of the person who runs the list, as well as for an initial password.

Once the list is made, the command will output lines like this:

## foo mailing list
foo:              "|/usr/lib/mailman/mail/mailman post foo"
foo-admin:        "|/usr/lib/mailman/mail/mailman admin foo"
foo-bounces:      "|/usr/lib/mailman/mail/mailman bounces foo"
foo-confirm:      "|/usr/lib/mailman/mail/mailman confirm foo"
foo-join:         "|/usr/lib/mailman/mail/mailman join foo"
foo-leave:        "|/usr/lib/mailman/mail/mailman leave foo"
foo-owner:        "|/usr/lib/mailman/mail/mailman owner foo"
foo-request:      "|/usr/lib/mailman/mail/mailman request foo"
foo-subscribe:    "|/usr/lib/mailman/mail/mailman subscribe foo"
foo-unsubscribe:  "|/usr/lib/mailman/mail/mailman unsubscribe foo"

These lines need to be added to /etc/aliases. Once added the newaliases command needs to be run.

Note that mailman will refuse to start up unless a list with the name 'mailman' is created.

==Starting Postfix and Mailman==

To start the Postfix and Mailman services:

service postfix start
service mailman start

To have these services run when the system is started:

chkconfig --levels 2345 postfix on
chkconfig --levels 2345 mailman on

To post a comment about this blog entry, go to the forum (self-signed https). New accounts may post once I approve the account.