Migration from Sendmail to Postfix

Nikolay Mihaylov, nmmm-at-nmmm-dot-nu

The document describes how to do migration from Sendmail mailer demon to Postfix mailer demon.

I assume you know sendmail very well. I assume you know how inetd works as well. I assume you do not know postfix at all. I also assume you have large sendmail installation with procmal and several domain names and several email addresses. My own installation was 579 domain names and 1767 email addresses, including system emails, rejection emails and catch-all's.


0. Why upgrade?

As I already said - My own e-mail  server serves 579 domain names and 1767 email addresses.

I have one more additional server that process e-mail forwarding only, done using SQL database. Latest estimations is there are 1830 domains, however most of them are not "live".

I believe both sendmail and postfix are very secure, if you configure them properly. I've running sendmail for several years, and I had security issues only first month until I configured sendmail properly. I still use sendmail for servers with smaller number of domain names.

I believe both sendmail and now postfix are very extensible.

Postfix is easier to configure, even I have been written my own sendmail.cf file.

However, the reason why I migrate is:
Postfix is faster and use less resources than sendmail.

I. Installation

Is better to install Postfix from package provided from your Linux distribution (often RPM). The installation will create several system users such postfix etc. The installation will create /etc/postfix directory as well.

After the installation, I recommend you make a copy of /etc/postfix and delete everything there, except following files:

all other files we will create later.

II. Configuration

1. master.cf

The file master.cf, is similar to /etc/inetd.conf . It describe on what port postfix works etc. It provides internal information for additional postfix demons too.

If we assume we have running sendmail on same server, first thing we need to do is to "move" postfix on different port:

part of /etc/postfix/master.cf
#smtp      inet  n       -       n       -       80      smtpd
2525       inet  n       -       n       -       -       smtpd

smtp and 2525 are the ports. smtp (25 port) is commented, and second instance is started in 2525 port.

80 is the max connection / max child number. in case of 2525 port we use default value (often 100)

2. main.cf

File main.cf contains the postfix configuration. We deleted the file, so we create a new one as follows:

#queue_directory         =       /var/spool/postfix
#command_directory       =       /usr/sbin

#daemon_directory       =       /usr/libexec/postfix
#mail_owner             =       postfix

myhostname              =       mx1.domain.com
mydomain                =       domain.com
mydestination           =       mx1.domain.com
virtual_alias_domains   =       /etc/postfix/local-host-names
virtual_alias_maps      =       hash:/etc/postfix/virtusertable, hash:/etc/postfix/aliases, hash:/etc/postfix/virtual
canonical_maps          =       hash:/etc/postfix/canonical

# NIS overrice
alias_maps              =

mailbox_command         =       /usr/bin/procmail

smtpd_helo_required     =       yes
disable_vrfy_command    =       yes

#inet_interfaces         =,,

mynetworks              =,

#permit_mx_backup_networks =

#smtpd_recipient_restrictions    =
#                permit_mynetworks,
#                permit_mx_backup,
#                reject_invalid_hostname,
#                reject_non_fqdn_sender,
#                reject_non_fqdn_recipient,
#                reject_unknown_sender_domain,
#                reject_unknown_recipient_domain,
#                reject_unauth_destination,
#                reject_unauth_pipelining
#                reject_non_fqdn_hostname

Now, the explanation

queue_directory and so on describe where the queue and so on are. Since we used RPM to install, we probably do not need to change these.

myhostname, mydomain is the main domain name. This does not mean we can not host additional domain names.

mydestination is good to be same as myhostname. This is default domain for emails. Currently emails will be something@mx1.domain.com . This is because we want to have something@domain.com as virtual address (will be explained later).

virtual_alias_domains is the local domain. get /etc/mail/local-host-names or /etc/sendmail.cw and copy file to /etc/postfix/local-host-names . File from sendmail is unchanged.

virtual_alias_maps - this is similar as /etc/mail/virtusertable. Because there are little difference, I will get back to this later.

canonical_maps - will get back to this later.

alias_maps - this is redhat / fedora option override, because they use NIS configuration.

mailbox_command - this tell postfix to use procmail as mailbox delivery. When you put this, your delivery immediately became same as in sendmail. I for example used sendmail + maildir, made via procmail. Now, postfix deliver mail to same mailboxes without any modifications.

smtpd_helo_required and disable_vrfy_command - these are good options for security.

inet_interfaces - this tell postfix on what interface to listen.

mynetworks - this tell postfix what network must be relayed. This is same as /etc/mail/access but is inline. In case you have several networks, you always can do:

part of /etc/postfix/main.cf
mynetworks              =       /etc/postfix/networks

/etc/postfix/networks looks like:

part or whole /etc/postfix/networks

One note here, postfix may have a file called /etc/postfix/access. It looks like /etc/mail/access, but it can not do following:

part or whole /etc/mail/access
#this is sendmail example, is not postfix file.
from:info@domain.com  REJECT

smtpd_recipient_restrictions - good security issues. After you go live, you want these, except probably permit_mx_backup. permit_mx_backup works exactly as sendmail option relay-based-on-mx.

3. Explanation on postfix and sendmail aliases files.

Both sendmail and postfix have aliases file (/etc/aliases, /etc/mail/aliases, /etc/postfix/aliases etc.), however there are some differences. Lets assume we have following:

/etc/aliases, /etc/mail/aliases, /etc/postfix/aliases etc.
# /etc/aliases

#name@aaa.com  :  bbbb
name@dom.com  :  ime@host.com
ime@dom.com   :  user@xxx.com

3.1. Sendmai:

in aliases, sendmail do not pay attention to domain name.

name@aaa.com is same as name@dom.com (and in such case is illegal)

however, on the right side, domain is important.

if we send mail to name@anydomain it will go to ime@anydomain, then will go to user@xxx.com . In case xxx.com is on different server it will be forwarded there. In case is on same server, it will be delivered to mailbox "user" (we assume there is no virtusertable)

3.2. Postfix:

well, here postfix is even worse :-)

in aliases postfix do not pay attention to any domain name. This is because aliases in postfix are for LOCAL DELIVERY ONLY.

the example file will be parsed as:

name@anydomain will directly go to mailbox "ime".
ime@anydomain will directly go to mailbox "user"

3.3. Problem fix:

These issues can be easy fixed if we view "aliases" file as additional "virtusertable" file.

part of /etc/postfix/main.cf
virtual_alias_maps      =       hash:/etc/postfix/virtusertable, hash:/etc/postfix/aliases, hash:/etc/postfix/virtual

in such case, 99% of cases, you can use sendmail aliases unchanged in postfix.

4. Sendmail virtusertable:

Even postfix have support for virtusertable file (i do not mean /etc/postfix/virtual), is better once again to use virtual_alias_maps

part of /etc/postfix/main.cf
virtual_alias_maps      =       hash:/etc/postfix/virtusertable, hash:/etc/postfix/aliases, hash:/etc/postfix/virtual

However there is one sendmail feature that is NOT supported in postfix. Here are an example:

user@dom.com   user_dom_com
name@dom.com   name_dom_com
@dom.com       all_dom_com

# here the problem:
@host.com      %1@dom.com 

host.com have same emails like dom.com. user@host.com go to user@dom.com and so on. Often this is 1 hosting with 2 or more domain names.

To solve this, we can use Postfix option called canonical_maps:

part of /etc/postfix/main.cf
canonical_maps          =       hash:/etc/postfix/canonical

You need to create a file called canonical :

@host.com      @dom.com

this can be done using grep:

grep '%1' /etc/mail/virtusertable | sed 's/%1//g' > canonical

when you do that, you will NOT NEED to remove "%1@dom.com" from sendmail virtusertable. you may use /etc/mail/virtusertable unchanged.

5. /etc/postfix/virtual

It is good to create this file, is same as virtusertable (and aliases), and to put any NEW emails/hosts there after you finish migration. At the beginning you start with empty file.

III. Maintenance and run postfix demon

1. Hash-es

Several of configuration files had "hash:" in front. This means that those files are similar to /etc/aliases.db. However instead of newaliases command, you need to use following commands:

cd /etc/postfix

postmap canonical
postmap virtual
postmap virtusertable
postalias aliases

Commands postmap and postalias working in same way, but postalias expect column as delimiter. If you want to be precise, you can use:

cd /etc/postfix

postmap hash:canonical
postmap hash:virtual
postmap hash:virtusertable
postalias hash:aliases

I personally created /usr/local/sbin/newpostmap file.

2. Start / stop / reload demon with "original" script

Postfix executable can be start/stop/reload in following way:

postfix -c /etc/postfix start
postfix -c /etc/postfix stop
postfix -c /etc/postfix reload

Note reload just reload the configuration. It does not restart the demon.

Often you may omit -c <conf directory>

3. Start / stop / restart demon with "redhat" script

This is the redhat / fedora init script

/etc/init.d/postfix start
/etc/init.d/postfix stop
/etc/init.d/postfix restart

Note restart stopping the demon, then start it again.

4. Queue watch.

there are two commands I am aware of - postqueue and qshape.

I noted that on very large queue, postqueue command works faster if you first stop postfix demon.

IV. Testing and more

If you follow all those steps, you will have postfix running on port 2525.

You may try telnet there and check if everything works. If it works for you, just stop sendmail, edit master.cf, make postfix works on port 25 (smtp), reload.

Congratulations :)

(c) 04.APR.2008, Nikolay Mihaylov