FreeBSD下完整的邮件服务器

以下操作建议以root身份操作。
后期维护强烈建议用普通用户+sudo(sudo需要另行安装配置)的方式进行操作。

此文实现以下功能: 目录:
Top

准备工作

设置固定IP

修改/etc/rc.conf,将网卡设置相关的行更改为以下形式:
hostname="mail.abc.com"      设置主机名,建议使用fqdn名称
ifconfig_hn0="inet 192.168.0.18 netmask 255.255.240.0"     设置固定IP和子网掩码,也可以写成 inet 192.168.0.18/24 的形式
defaultroute="192.168.0.1"   设置网关地址
使用命令重启网卡:
/etc/netstart restart

更改系统源

先编辑/etc/freebsd-update.conf文件,将ServerName的值修改为update.FreeBSD.cn。
然后运行以下命令对系统进行更新:
freebsd-update fetch install
freebsd.cn已经无法使用,且官方源速度尚可,故不需要做换源操作。下同。

更改pkg源

编辑/etc/pkg/FreeBSD.conf文件,将url指向更快的源,比如:
url: "pkg+http://pkg.FreeBSD.cn/${ABI}/quarterly
“quarterly”表示季度更新(更加稳定),也可以改成“latest”使用最新更新。

更改ports源(本文未用,仅作备查)

修改/etc/portsnap.conf文件,将SERVERNAVE的值改为portsnap.FreeBSD.cn
然后运行以下命令更新ports树:
portsnap auto
再创建/etc/make.conf,添加以下内容以使用更快的ports源:
MASTER_SITE_OVERRIDE?=\
  http://mirrors.ustc.edu.cn/freebsd-ports/distfiles/${DIST_SUBDIR}/ \
  http://ports.freebsd.cn/ports-distfiles/${DIST_SUBDIR}/  \
  http://distcache.freebsd.org/ports-distfiles/${DIST_SUBDIR}/ 

创建管理邮件的系统用户和虚拟组

# pw groupadd vmail -g 500         创建vmail组,组id为500
# pw useradd vmail -g 500 -u 500   创建vmail用户,用户id为500,且为vmail组成员

创建用于存放邮件的目录,并授权给vmail用户

对于使用ZFS文件系统的系统,可以为邮件单独创建一个zfs文件系统:
# zfs create zroot/var/vmail
# chown vmail:vmail /var/vmail
而对于非ZFS系统,需要为邮件系统创建一个用于保存邮件的目录:
# mkdir -p /var/vmail
# chown vmail:vmail /var/vmail

自认证证书

首先执行以下命令制作自认证证书:
# mkdir /etc/ssl/mailserver
# cd /etc/ssl/mailserver
# openssl genrsa -out mailserver.key
# openssl req -new -x509 -days 3650 -key mailserver.key -out mailserver.crt -subj "/C=CN/ST=GuangDong/L=GuangZhou/O=mycompany/OU=mydepartment/CN=mail.abc.com/CN=mail.xyz.com.cn"
以上命令制作的证书包含了两个CN(common name),可以根据实际情况增加或减少,多CN以斜杠(/)分隔
然后执行以下命令创建软链接以符合dovecot关于证书的设置(/usr/local/etc/dovecot/conf.d/10-ssl.conf):
# mkdir /etc/ssl/private
# ln -s /etc/ssl/mailserver/mailserver.crt /etc/ssl/certs/dovecot.pem
# ln -s /etc/ssl/mailserver/mailserver.key /etc/ssl/private/dovecot.pem
注意:
今天(2022/8/11)将服务器从13.1升级到13.1-p1,发现无法收发邮件。以为是更新需要重启。
重启后看到提示说未找到/etc/ssl/certs/dovecot.pem,dovecot未能启动。
怀疑是系统升级的时候将/etc/ssl/certs目录整个清空重做了,顺便也带走了里面的软链接。
针对这个问题,建议将证书文件放到自己的目录里,比如/var/vmail/ssl/中。

然后修改/usr/local/etc/dovecot/conf.d/10-ssl.conf和/usr/local/etc/postfix/main.cf两个文件,将与证书相关的配置指向正确的位置。

nginx+php

安装nginx和php80:
pkg install nginx php80
将nginx和php-fpm加入rc.conf:
# sysrc nginx_enable="yes"
# sysrc php_fpm_enable="yes"
修改nginx的配置文件,以适配php:
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        location ~ \.php$ {
            root   /usr/local/www/nginx;
            fastcgi_pass   127.0.0.1:9000;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
            include        fastcgi_params;
        }

数据库

安装miariadb-server:
pkg install mariadb106-server
将mariadb加入rc.conf:
# sysrc mysql_enable="yes"
mariadb的服务名为mysql-server,例如,要重启mariadb数据库,可执行以下命令:
service mysql-server restart
进入mysql为roundcube创建数据库和用户:
create database roundcubemail;
grant all privileges on roundcubemail.* to roundcube@localhost  identified by '123456';

ipfw

编辑/etc/rc.conf,加入以下行:
firewall_enable="yes"
firewall_type="open
firewall_script="/etc/ipfw.rules"
firewall_logging="yes"
firewall_logif="yes"
fail2ban与ipfw配合使用时会有个问题,那就是fail2ban会把要拦截的IP“追加”到规则列表中。
而对于采用“黑名单”机制的防火墙系统来讲,一般的流程是:先拦截黑名单里的IP,最后会有一条允许其他的任意连接。
fail2ban却会将黑名单IP添加到“最后一条”之后。
根据ipfw的运行机制,每条规则都有一个编号(1-65534),按编号顺序检测,如果编号相同,则按出现的先后顺序来执行检测。一旦检测到符合某条规则,则后续的规则会被忽略。
(这句存疑)如果一条规则没有写编号,会默认其编号为100,如果100被占用,则顺延至下一个未被占用的编号。
为避免fail2ban将规则追加到最后一行而变成无效规则,可以通过ipfw的table来解决。即,将要拦截的ip写入一个table里,然后基于这个table设立一个靠前的规则。
如下所示:
编辑/etc/ipfw.rules
#! /bin/sh
cmd="ipfw -q add"
ipfw -q -f flush
pif="hn0"
ipfw add deny all from 'table(1)' to any
$cmd 65534 allow all from any to any
关于fail2ban处理table 1的方式,放在此文末尾的fail2ban设置里说。

安装需要的包,并进行初始配置

dovecot

pkg install dovecot
将dovecot的配置文件复制到指定位置:
# cp -R /usr/local/etc/dovecot/example-config/* \
        /usr/local/etc/dovecot
运行以下命令将dovecot加入到rc.conf:
# sysrc dovecot_enable="YES"

postfix

pkg install postfix
安装完成后根据做如下操作:
# mkdir -p /usr/local/etc/mail
# install -m 0644 /usr/local/share/postfix/mailer.conf.postfix /usr/local/etc/mail/mailer.conf
# vi /etc/periodic.conf
  daily_clean_hoststat_enable="NO"
  daily_status_mail_rejects_enable="NO"
  daily_status_include_submit_mailq="NO"
  daily_submit_queuerun="NO"
运行以下命令将postfix加入到rc.conf,并停用sendmail:
# sysrc postfix_enable="YES"
# sysrc sendmail_enable="NONE"

防病毒及垃圾邮件

# pkg install amavisd-new clamav-daemon spamassassin
# pkg install 7-zip lrzip cabextract tnef
安装spamassassin后需要先运行一次sa-update(jail内可能会提示gpg:警告:正在使用不安全的内存。忽略即可)。
然后在/etc/rc.conf中加入以下行:
# 以下三行启动clamav相关服务,freshclam会自动更新病毒库
clamav_clamd_enable="YES"
clamav_freshclam_enable="YES"
clamav_milter_enable="YES"
# 以下行启动amavisd服务,若本地主机名不是FQDN,服务将无法正常启动
amavisd_enalbe="YES"
# 以下启动spamassassin服务,
spamd_enable="YES"
手动启动spamd的命令为:
service sa-spamd start
修改/etc/group,将clamav加入到vscan组:
vscan:*:110:clamav
某次做pkg upgrade时,更新了spamssassin,sa-spamd服务无法启动,提示:
child process [1660] exited or timed out without signaling production of a PID file: exit 255 at /usr/local/bin/spamd line 3034.
同时,下面的amavisd服务也无法启动。
解决方法是执行以下命令后重启服务器:
sa-update
推测可能是spamassassin更新时将规则冲掉了,需要重新建立规则。

以上安装完成后,使用命令service servicename start启动对应的服务,或者重启系统来启动它们。
使用命令sockstat -l4查看开放了哪些端口。

roundcube

安装roundcube-php80:
pkg install roundcube-php80
安装程序会在/usr/local/www/目录中创建roundcube目录,存放roundcube的代码。

fail2ban

安装fail2ban:
pkg install py39-fail2ban
将fail2ban加入到rc.conf:
sysrc fail2ban_enable="yes"

配置dovecot

虚拟账号

先生成用户密码文件/usr/local/etc/dovecot/users,此文件用于保存用户名及密码,格式类似:
XXX@abc.com:{plain}pass123
冒号前面为账号名,冒号后面为密码。
可以使用命令doveadm pw -p pass123生成加密的密码:
root@mail:/usr/local/etc/dovecot# doveadm pw -p pass123
{CRYPT}$2y$05$aa.dmN2oO/lMMRJJ.xbvhu26pPQ32pN7Uu5dZhWVSYjxLg8FtTI9i
将加密密码写入密码文件:
XXX@abc.com:{CRYPT}$2y$05$aa.dmN2oO/lMMRJJ.xbvhu26pPQ32pN7Uu5dZhWVSYjxLg8FtTI9i
实际上以下两行是等效的:
XXX@abc.com:{plain}pass123
XXX@abc.com:{CRYPT}$2y$05$aa.dmN2oO/lMMRJJ.xbvhu26pPQ32pN7Uu5dZhWVSYjxLg8FtTI9i
而且此文件中密码加密方式可以混用,即A用户可以用SHA512,B用户可以用SHA256。
这方便从其他系统将账号密码直接复制过来使用。

然后修改/usr/local/etc/dovecot/conf.d/10-auth.conf文件,引用auth-passwdfile.conf.ext:
#!include auth-system.conf.ext        默认未被注释,此文件配置系统用户认证
!include auth-passwdfile.conf.ext     默认被注释,此文件配置密码文件认证
再修改/usr/local/etc/dovecot/conf.d/auth-passwdfile.conf.ext文件,内容如下:
passdb {
 driver = passwd-file
 args = scheme=CRYPT username_format=%u /usr/local/etc/dovecot/users   此处指定密码加密,以及用户名格式。%u表示完整的邮件地址。
}
userdb {
 driver = static
 args = uid=vmail gid=vmail home=/var/vmail/%d/%n  
%d表示邮件地址的域名部分;%n表示邮件地址的用户名部分。这样设置是表示将相同域名的虚拟邮箱放到同一个目录下,然后按用户再分。 }

修改邮件存储方式及位置

编辑/usr/local/etc/dovecot/conf.d/10-mail.conf,将mail_location的值修改为以下内容:
mail_location = maildir:~/Maildir

namespace

10-mail.conf中定义namespace类型: 15-mailboxs.conf中的namespace inbox{}中定义邮箱中的文件夹,格式如下:
mailbox Sent {
  auto = subscribe
  special_use = \Sent
}
说明:
# auto:
#   Indicates whether the mailbox with this name is automatically created
#   implicitly when it is first accessed. The user can also be automatically
#   subscribed to the mailbox after creation. The following values are
#   defined for this setting:
#   指示首次访问时是否隐式自动创建具有此名称的邮箱。
#   用户还可以在创建后自动订阅邮箱。为此设置定义了以下值:
#
#     no        - Never created automatically.(从不自动创建)
#     create    - Automatically created, but no automatic subscription.(自动创建但不自动订阅)
#     subscribe - Automatically created and subscribed.(自动创建并订阅)
#
# special_use:
#   A space-separated list of SPECIAL-USE flags (RFC 6154) to use for the
#   mailbox. There are no validity checks, so you could specify anything
#   you want in here, but it's not a good idea to use flags other than the
#   standard ones specified in the RFC:
#   用于邮箱的专用标志(RFC 6154)的以空格分隔的列表。
#   没有有效性检查,所以你可以在这里指定任何你想要的东西,
#   但使用RFC中指定的标准标志之外的标志不是一个好主意。
#
#     \All       - This (virtual) mailbox presents all messages in the
#                  user's message store.
#     \Archive   - This mailbox is used to archive messages.(归档邮件)
#     \Drafts    - This mailbox is used to hold draft messages.(草稿邮件)
#     \Flagged   - This (virtual) mailbox presents all messages in the
#                  user's message store marked with the IMAP \Flagged flag.(被标记的邮件)
#     \Important - This (virtual) mailbox presents all messages in the
#                  user's message store deemed important to user.(重要邮件)
#     \Junk      - This mailbox is where messages deemed to be junk mail
#                  are held.(垃圾邮件)
#     \Sent      - This mailbox is used to hold copies of messages that
#                  have been sent.(已发送邮件)
#     \Trash     - This mailbox is used to hold messages that have been
#                  deleted.(已删除邮件)

共享验证方式

修改/etc/dovecot/conf.d/10-master.conf,去掉以下三行前面的注释,使得postfix可以使用dovecot的认证方法验证客户端连接:
 unix_listener /var/spool/postfix/private/auth {
  mode = 0666
 }

以下是完整的配置输出:

root@mail:/usr/local/etc/dovecot/conf.d # doveconf -nP
# 2.3.19.1 (9b53102964): /usr/local/etc/dovecot/dovecot.conf
# OS: FreeBSD 13.1-RELEASE amd64
# Hostname: mail.abc.com
auth_mechanisms = plain login
mail_location = maildir:~/Maildir
namespace inbox {
  inbox = yes
  location =
  mailbox Drafts {
    special_use = \Drafts
  }
  mailbox Junk {
    special_use = \Junk
  }
  mailbox Sent {
    special_use = \Sent
  }
  mailbox "Sent Messages" {
    special_use = \Sent
  }
  mailbox Trash {
    special_use = \Trash
  }
  prefix =
}
passdb {
  args = scheme=CRYPT username_format=%u /var/vmail/user-passwd
  driver = passwd-file
}
service auth {
  unix_listener /var/spool/postfix/private/auth {
    mode = 0666
  }
}
ssl = required
ssl_cert = </etc/ssl/certs/dovecot.pem
ssl_key = </etc/ssl/private/dovecot.pem
userdb {
  args = uid=vmail gid=vmail home=/var/vmail/%d/%n
  driver = static
}

以下是Debian系统中iRedMail的输出:

mailman@mail:~$ doveconf -nP
# 2.3.13 (89f716dc2): /etc/dovecot/dovecot.conf
# Pigeonhole version 0.5.13 (cdd19fe3)
# OS: Linux 5.10.0-15-amd64 x86_64 Debian 11.3
# Hostname: mail.abc.org
auth_master_user_separator = *
auth_mechanisms = PLAIN LOGIN
deliver_log_format = from=%{from}, envelope_sender=%{from_envelope}, subject=%{subject}, msgid=%m, size=%{size}, delivery_time=%{delivery_time}ms, %$
dict {
  acl = mysql:/etc/dovecot/dovecot-share-folder.conf
  lastlogin = mysql:/etc/dovecot/dovecot-last-login.conf
  quotadict = mysql:/etc/dovecot/dovecot-used-quota.conf
}
first_valid_uid = 2000
last_valid_uid = 2000
listen = * [::]
login_log_format_elements = user=<%u> method=%m rip=%r lip=%l mpid=%e %c %k session=<%{session}>
mail_gid = 2000
mail_location = maildir:%Lh/Maildir/:INDEX=%Lh/Maildir/
mail_plugins = quota mailbox_alias acl mail_log notify
mail_uid = 2000
managesieve_notify_capability = mailto
managesieve_sieve_capability = fileinto reject envelope encoded-character vacation subaddress comparator-i;ascii-numeric relational regex imap4flags copy include variables body enotify environment mailbox date index ihave duplicate mime foreverypart extracttext
namespace {
  inbox = yes
  location =
  mailbox Archive {
    auto = no
    special_use = \Archive
  }
  mailbox Archives {
    auto = no
    special_use = \Archive
  }
  mailbox "Deleted Messages" {
    auto = no
    special_use = \Trash
  }
  mailbox Drafts {
    auto = subscribe
    special_use = \Drafts
  }
  mailbox Junk {
    auto = subscribe
    special_use = \Junk
  }
  mailbox "Junk E-mail" {
    auto = no
    special_use = \Junk
  }
  mailbox Sent {
    auto = subscribe
    special_use = \Sent
  }
  mailbox "Sent Items" {
    auto = no
    special_use = \Sent
  }
  mailbox "Sent Messages" {
    auto = no
    special_use = \Sent
  }
  mailbox Spam {
    auto = no
    special_use = \Junk
  }
  mailbox Trash {
    auto = subscribe
    special_use = \Trash
  }
  prefix =
  separator = /
  type = private
}
namespace {
  list = children
  location = maildir:%%Lh/Maildir/:INDEX=%%Lh/Maildir/Shared/%%Ld/%%Ln
  prefix = Shared/%%u/
  separator = /
  subscriptions = yes
  type = shared
}
passdb {
  args = /etc/dovecot/dovecot-mysql.conf
  driver = sql
}
passdb {
  args = /etc/dovecot/dovecot-master-users
  driver = passwd-file
  master = yes
}
plugin {
  acl = vfile
  acl_shared_dict = proxy::acl
  last_login_dict = proxy::lastlogin
  last_login_key = last-login/%s/%u/%d
  mail_log_events = delete undelete expunge copy mailbox_create mailbox_delete mailbox_rename
  mail_log_fields = uid box msgid size from subject flags
  mailbox_alias_new = Sent Messages
  mailbox_alias_new2 = Sent Items
  mailbox_alias_old = Sent
  mailbox_alias_old2 = Sent
  quota = dict:user::proxy::quotadict
  quota_grace = 10%%
  quota_status_nouser = DUNNO
  quota_status_overquota = 552 5.2.2 Mailbox is full
  quota_status_success = DUNNO
  quota_warning = storage=100%% quota-warning 100 %u
  quota_warning2 = storage=95%% quota-warning 95 %u
  quota_warning3 = storage=90%% quota-warning 90 %u
  quota_warning4 = storage=85%% quota-warning 85 %u
  sieve = ~/sieve/dovecot.sieve
  sieve_before = /var/vmail/sieve/dovecot.sieve
  sieve_dir = ~/sieve
  sieve_global_dir = /var/vmail/sieve
  sieve_max_redirects = 30
  sieve_vacation_send_from_recipient = yes
}
protocols = pop3 imap sieve lmtp
service auth {
  unix_listener /var/spool/postfix/private/dovecot-auth {
    group = postfix
    mode = 0666
    user = postfix
  }
  unix_listener auth-master {
    group = vmail
    mode = 0666
    user = vmail
  }
  unix_listener auth-userdb {
    group = vmail
    mode = 0660
    user = vmail
  }
}
service dict {
  unix_listener dict {
    group = vmail
    mode = 0660
    user = vmail
  }
}
service imap-login {
  process_limit = 500
  service_count = 1
}
service lmtp {
  executable = lmtp -L
  inet_listener lmtp {
    address = 127.0.0.1
    port = 24
  }
  process_min_avail = 5
  unix_listener /var/spool/postfix/private/dovecot-lmtp {
    group = postfix
    mode = 0600
    user = postfix
  }
  user = vmail
}
service managesieve-login {
  inet_listener sieve {
    address = 127.0.0.1
    port = 4190
  }
}
service pop3-login {
  service_count = 1
}
service quota-status {
  client_limit = 1
  executable = quota-status -p postfix
  inet_listener {
    address = 127.0.0.1
    port = 12340
  }
}
service quota-warning {
  executable = script /usr/local/bin/dovecot-quota-warning.sh
  unix_listener quota-warning {
    group = vmail
    mode = 0660
    user = vmail
  }
}
service stats {
  fifo_listener stats-mail {
    mode = 0644
    user = vmail
  }
  inet_listener {
    address = 127.0.0.1
    port = 24242
  }
  unix_listener stats-writer {
    group = vmail
    mode = 0660
    user = vmail
  }
}
ssl = required
ssl_cert = </etc/ssl/certs/iRedMail.crt
ssl_cipher_list = EECDH+CHACHA20:EECDH+AESGCM:EDH+AESGCM:AES256+EECDH
ssl_dh = </etc/ssl/dh2048_param.pem
ssl_key = </etc/ssl/private/iRedMail.key
ssl_min_protocol = TLSv1.2
ssl_prefer_server_ciphers = yes
syslog_facility = local5
userdb {
  args = /etc/dovecot/dovecot-mysql.conf
  driver = sql
}
protocol lda {
  lda_mailbox_autocreate = yes
  lda_mailbox_autosubscribe = yes
  mail_plugins = quota mailbox_alias acl mail_log notify sieve
}
protocol lmtp {
  lmtp_save_to_detail_mailbox = yes
  mail_plugins = quota mailbox_alias acl mail_log notify sieve
  recipient_delimiter = +
}
protocol imap {
  imap_client_workarounds = tb-extra-mailbox-sep
  mail_max_userip_connections = 30
  mail_plugins = quota mailbox_alias acl mail_log notify imap_quota imap_acl last_login
}
protocol pop3 {
  mail_max_userip_connections = 30
  mail_plugins = quota mailbox_alias acl mail_log notify last_login
  pop3_client_workarounds = outlook-no-nuls oe-ns-eoh
  pop3_uidl_format = %08Xu%08Xv
}


以上完成后重启dovecot服务。

配置postfix

修改/etc/postfix/main.cf

使用以下命令创建简版main.cf文件:
# cd /usr/local/etc/postfix
# more main.cf | grep -v ^# | grep -v ^$ > main.cf.new
# mv main.cf main.cf.bk
# mv main.cf.new main.cf
然后追加一些内容得到:
root@mail:/usr/local/etc/postfix # more main.cf
compatibility_level = 3.7
queue_directory = /var/spool/postfix
command_directory = /usr/local/sbin
daemon_directory = /usr/local/libexec/postfix
data_directory = /var/db/postfix
mail_owner = postfix
unknown_local_recipient_reject_code = 550
mynetworks_style = subnet
debug_peer_level = 2
debugger_command =
        PATH=/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin
        ddd $daemon_directory/$process_name $process_id & sleep 5
sendmail_path = /usr/local/sbin/sendmail
newaliases_path = /usr/local/bin/newaliases
mailq_path = /usr/local/bin/mailq
setgid_group = maildrop
html_directory  = /usr/local/share/doc/postfix
manpage_directory = /usr/local/man
sample_directory = /usr/local/etc/postfix
readme_directory = /usr/local/share/doc/postfix
inet_protocols = ipv4
smtp_tls_CApath = /etc/ssl/certs
shlib_directory = /usr/local/lib/postfix
meta_directory = /usr/local/libexec/postfix

# 以上为系统默认内容,不做修改。

# 以下配置postfix使用dovecot验证
smtpd_sasl_type = dovecot
smtpd_sasl_auth_enable = yes
smtpd_sasl_security_options = noanonymous
broken_sasl_auth_clients = yes
smtpd_sasl_path = private/auth

# 以下设置虚拟账号
virtual_mailbox_base = /var/vmail
virtual_mailbox_domains = hash:/var/vmail/postmaps/vmail_domains
virtual_mailbox_maps = hash:/var/vmail/postmaps/vmail_mailbox
virtual_transport = virtual
virtual_uid_maps = static:500
virtual_gid_maps = static:500
virtual_alias_maps = hash:/var/vmail/postmaps/virtual_alias
# 虚拟邮箱限制1.5G
virtual_mailbox_limit = 1572864000

# 以下配置SSL
smtpd_tls_security_level = may
smtpd_tls_received_header = yes
#smtpd_enforce_tls = yes   此句在2024/4/20日更新后被抛弃
smtpd_tls_loglevel = 1
smtp_tls_loglevel = 1
smtpd_tls_cert_file = /etc/ssl/certs/dovecot.pem
smtpd_tls_key_file = /etc/ssl/private/dovecot.pem
smtp_tls_note_starttls_offer = yes

enable_long_queue_ids = yes
smtpd_reject_unlisted_recipient = yes
smtpd_reject_unlisted_sender = yes

#防垃圾邮件
smtpd_helo_required = yes
smtpd_helo_restrictions =
  permit_mynetworks
  reject_invalid_hostname
smtpd_sender_restrictions =
  permit_mynetworks
  reject_non_fqdn_sender
  reject_unknown_sender_domain
smtpd_recipient_restrictions =
  permit_sasl_authenticated
  permit_mynetworks
  reject_unauth_destination
  reject_non_fqdn_recipient
  reject_unknown_recipient_domain
smtpd_data_restrictions =
  permit_mynetworks
  reject_unauth_pipelining
smtpd_relay_restrictions =
  permit_mynetworks
  permit_sasl_authenticated
  defer_unauth_destination

#调用amavis-new检查病毒及垃圾邮件
content_filter = smtp-amavis:[127.0.0.1]:10024
receive_override_options = no_address_mappings
smtpd_proxy_options = speed_adjust

# 邮件大小限制到150M
message_size_limit = 157286400
mailbox_size_limit = 0
注意,/etc/postfix/main.cf的mydestination中不能包含virtual_mailbox中的域名,也就是说,域名不能同时出现在这两个地方

修改master.cf文件

得到以下内容:
root@mail:/usr/local/etc/postfix # more master.cf
smtp      inet  n       -       n       -       -       smtpd
pickup    unix  n       -       n       60      1       pickup
cleanup   unix  n       -       n       -       0       cleanup
qmgr      unix  n       -       n       300     1       qmgr
tlsmgr    unix  -       -       n       1000?   1       tlsmgr
rewrite   unix  -       -       n       -       -       trivial-rewrite
bounce    unix  -       -       n       -       0       bounce
defer     unix  -       -       n       -       0       bounce
trace     unix  -       -       n       -       0       bounce
verify    unix  -       -       n       -       1       verify
flush     unix  n       -       n       1000?   0       flush
proxymap  unix  -       -       n       -       -       proxymap
proxywrite unix -       -       n       -       1       proxymap
smtp      unix  -       -       n       -       -       smtp
relay     unix  -       -       n       -       -       smtp
        -o syslog_name=postfix/$service_name
showq     unix  n       -       n       -       -       showq
error     unix  -       -       n       -       -       error
retry     unix  -       -       n       -       -       error
discard   unix  -       -       n       -       -       discard
local     unix  -       n       n       -       -       local
virtual   unix  -       n       n       -       -       virtual
lmtp      unix  -       -       n       -       -       lmtp
anvil     unix  -       -       n       -       1       anvil
scache    unix  -       -       n       -       1       scache
postlog   unix-dgram n  -       n       -       1       postlogd
# 以上为系统默认内容,不做修改
# submission,开放587端口,强制TLS连接
submission   inet   n   -   n   -   -   smtpd
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=may
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_client_restrictions=permit_mynetworks,permit_sasl_authenticated,reject

# smtpd,开放465端口,强制SSL连接
465   inet   n   -   n   -   -   smtpd
  -o syslog_name=postfix/smtps
  -o smtpd_tls_wrappermode=yes
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_client_restrictions=permit_sasl_authenticated,reject

# Amavisd 集成
smtp-amavis unix -   -   n   -   4   smtp
  -o syslog_name=postfix/amsvis
  -o smtp_data_done_timeout=1200
  -o smtp_send_xforward_command=yes
#  -o disable_dns_lookups=yes    此句在2024/4/20日更新后被抛弃
  -o max_use=20

# 用于Amavisd返回邮件到postfix
127.0.0.1:10025 inet  n   -   n   -   -   smtpd
  -o syslog_name=postfix/10025
  -o content_filter=
  -o mynetworks_style=host
  -o mynetworks=127.0.0.0/8
  -o local_recipient_maps=
  -o relay_recipient_maps=
  -o strict_rfc821_envelopes=yes
  -o smtp_tls_security_level=none
  -o smtpd_tls_security_level=none
  -o smtpd_restriction_classes=
  -o smtpd_delay_reject=no
  -o smtpd_client_restrictions=permit_mynetworks,reject
  -o smtpd_helo_restrictions=
  -o smtpd_sender_restrictions=
  -o smtpd_recipient_restrictions=permit_mynetworks,reject
  -o smtpd_end_of_data_restrictions=
  -o smtpd_error_sleep_time=0
  -o smtpd_soft_error_limit=1001
  -o smtpd_hard_error_limit=1000
  -o smtpd_client_connection_count_limit=0
  -o smtpd_client_connection_rate_limit=0
  -o receive_override_options=no_header_body_checks,no_unknown_recipient_checks,no_address_mappings

Debian下iRedMail的main.cf:

mailman@mail:/etc/postfix$ more main.cf
# --------------------
# INSTALL-TIME CONFIGURATION INFORMATION
# 安装时配置信息
# location of the Postfix queue. Default is /var/spool/postfix.
# postfix队列路径,默认为/var/spool/postfix
queue_directory = /var/spool/postfix

# location of all postXXX commands. Default is /usr/sbin.
# postXXX命令群的路径,默认为/usr/sbin
command_directory = /usr/sbin

# location of all Postfix daemon programs (i.e. programs listed in the
# master.cf file). This directory must be owned by root.
# Default is /usr/libexec/postfix
# postfix守护进程(比如master.cf文件列出的程序)的路径,此目录只能为root所有。
daemon_directory = /usr/lib/postfix/sbin

# location of Postfix-writable data files (caches, random numbers).
# This directory must be owned by the mail_owner account (see below).
# Default is /var/lib/postfix.
# postfix可写数据文件的目录。此目录只能为mail_owner账号所有。
data_directory = /var/lib/postfix

# owner of the Postfix queue and of most Postfix daemon processes.
# Specify the name of a user account THAT DOES NOT SHARE ITS USER OR GROUP ID
# WITH OTHER ACCOUNTS AND THAT OWNS NO OTHER FILES OR PROCESSES ON THE SYSTEM.
# In particular, don't specify nobody or daemon. PLEASE USE A DEDICATED USER.
# Default is postfix.
# postfix队列和大多数守护进程的所有者。
# 用户和组ID不得与其他账号共享,且不拥有系统上其他文件或进程的权限。特别是不要指定nobody或daemon。
# 应使用专用账号。
mail_owner = postfix

# The following parameters are used when installing a new Postfix version.
# 以下参数在安装新版本postfix时使用。
# sendmail_path: The full pathname of the Postfix sendmail command.
# This is the Sendmail-compatible mail posting interface.
# 
sendmail_path = /usr/sbin/sendmail

# newaliases_path: The full pathname of the Postfix newaliases command.
# This is the Sendmail-compatible command to build alias databases.
#
newaliases_path = /usr/bin/newaliases

# full pathname of the Postfix mailq command.  This is the Sendmail-compatible
# mail queue listing command.
mailq_path = /usr/bin/mailq

# group for mail submission and queue management commands.
# This must be a group name with a numerical group ID that is not shared with
# other accounts, not even with the Postfix account.
setgid_group = postdrop

# external command that is executed when a Postfix daemon program is run with
# the -D option.
# 使用-D选项运行postfix守护程序时执行的外部命令。
# Use "command .. & sleep 5" so that the debugger can attach before
# the process marches on. If you use an X-based debugger, be sure to
# set up your XAUTHORITY environment variable before starting Postfix.
#
debugger_command =
    PATH=/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin
    ddd $daemon_directory/$process_name $process_id & sleep 5

debug_peer_level = 2

# --------------------
# CUSTOM SETTINGS
# 自定义设置

# SMTP server response code when recipient or domain not found.
# 未找到收件人或域时,SMTP服务器反馈的代码
unknown_local_recipient_reject_code = 550

# Do not notify local user.
# 不通知本地用户
biff = no

# Disable the rewriting of "site!user" into "user@site".
# 不将"site!user"重写为"user@site"
swap_bangpath = no

# Disable the rewriting of the form "user%domain" to "user@domain".
# 不将"user%domain"重写为"user@domain"
allow_percent_hack = no

# Allow recipient address start with '-'.
# 允许收件人地址以'-'开头
allow_min_user = no

# Disable the SMTP VRFY command. This stops some techniques used to
# harvest email addresses.
# 禁用SMTP VRFY命令。这可以阻止一些用于获取电子邮件地址的技术。
disable_vrfy_command = yes

# Enable both IPv4 and/or IPv6: ipv4, ipv6, all.
# 允许IPv4和/或IPv6。可用值为ipv4,ipv6,all
inet_protocols = all

# Enable all network interfaces.
# 允许所有网卡
inet_interfaces = all

#
# TLS settings.
# TLS设置
# SSL key, certificate, CA
# SSL密钥,证书,认证机构
smtpd_tls_key_file = /etc/ssl/private/iRedMail.key
smtpd_tls_cert_file = /etc/ssl/certs/iRedMail.crt
smtpd_tls_CAfile = /etc/ssl/certs/iRedMail.crt
smtpd_tls_CApath = /etc/ssl/certs

#
# Disable SSLv2, SSLv3
# 禁止SSLv2和SSLv3
smtpd_tls_protocols = !SSLv2 !SSLv3
smtpd_tls_mandatory_protocols = !SSLv2 !SSLv3

smtp_tls_protocols = !SSLv2 !SSLv3
smtp_tls_mandatory_protocols = !SSLv2 !SSLv3

lmtp_tls_protocols = !SSLv2 !SSLv3
lmtp_tls_mandatory_protocols = !SSLv2 !SSLv3

#
# Fix 'The Logjam Attack'.
# logjam攻击RSA密钥交换,是TLS协议中的缺陷
smtpd_tls_exclude_ciphers = aNULL, eNULL, EXPORT, DES, RC4, MD5, PSK, aECDH, EDH-DSS-DES-CBC3-SHA, EDH-RSA-DES-CDC3-SHA, KRB5-DE5, CBC3-SHA
smtpd_tls_dh512_param_file = /etc/ssl/dh512_param.pem
smtpd_tls_dh1024_param_file = /etc/ssl/dh2048_param.pem
# 使用命令openssl dhparam -out dh512_param.pem 512生成dh512_param.pem文件
# smtpd_tls_dh1024_param_file可以指向1024位dh参数文件,也可以指向2048位dh参数文件。

tls_random_source = dev:/dev/urandom

# Log only a summary message on TLS handshake completion — no logging of client
# certificate trust-chain verification errors if client certificate
# verification is not required. With Postfix 2.8 and earlier, log the summary
# message, peer certificate summary information and unconditionally log
# trust-chain verification errors.
# 仅在TLS握手完成时记录摘要消息-如果不需要客户端证书验证,则不记录客户端证书信任链验证错误。
# 使用Postfix 2.8及更早版本,记录摘要消息、对等证书摘要信息,并无条件记录信任链验证错误。
smtp_tls_loglevel = 1
smtpd_tls_loglevel = 1

# Opportunistic TLS: announce STARTTLS support to remote SMTP clients, but do
# not require that clients use TLS encryption.
# 机会主义TLS:宣布STARTTLS支持远程SMTP客户端,但不要求客户端使用TLS加密。
smtpd_tls_security_level = may

# Produce `Received:` message headers that include information about the
# protocol and cipher used, as well as the remote SMTP client CommonName and
# client certificate issuer CommonName.
# This is disabled by default, as the information may be modified in transit
# through other mail servers. Only information that was recorded by the final
# destination can be trusted.
# 生成‘已接收:’消息头,其中包括有关所用协议和密码的信息,以及远程SMTP客户端CommonName和客户端证书颁发者的CN。
# 默认情况下是禁用的,因为信息可能在通过其他邮件服务器传输时被修改。只有最终目的地记录的信息才能被信任。
#smtpd_tls_received_header = yes

# Opportunistic TLS, used when Postfix sends email to remote SMTP server.
# Use TLS if this is supported by the remote SMTP server, otherwise use
# plaintext.
# 投机性TLS,当Postfix向远程SMTP服务器发送电子邮件时使用。如果远程SMTP服务器支持TLS,则使用TLS,否则使用明文。
# References:
#   - http://www.postfix.org/TLS_README.html#client_tls_may
#   - http://www.postfix.org/postconf.5.html#smtp_tls_security_level
smtp_tls_security_level = may

# Use the same CA file as smtpd.
# 使用与smtpd相同的CA文件
smtp_tls_CApath = /etc/ssl/certs
smtp_tls_CAfile = $smtpd_tls_CAfile
smtp_tls_note_starttls_offer = yes

# Enable long, non-repeating, queue IDs (queue file names).
# 启用长且不重复的队列ID(队列文件名)。
# The benefit of non-repeating names is simpler logfile analysis and easier
# queue migration (there is no need to run "postsuper" to change queue file
# names that don't match their message file inode number).
enable_long_queue_ids = yes

# Reject unlisted sender and recipient
# 拒绝未列出的发件人和收件人
smtpd_reject_unlisted_recipient = yes
smtpd_reject_unlisted_sender = yes

# Header and body checks with PCRE table
# 使用RCRE表检查邮件头和邮件体
header_checks = pcre:/etc/postfix/header_checks
body_checks = pcre:/etc/postfix/body_checks.pcre

# A mechanism to transform commands from remote SMTP clients.
# 转换来自远程SMTP客户端的命令的机制。
# This is a last-resort tool to work around client commands that break
# interoperability with the Postfix SMTP server. Other uses involve fault
# injection to test Postfix's handling of invalid commands.
# 这是解决客户端命令破坏与Postfix SMTP服务器互操作性的最后手段。
# 其他用途包括故障注入,以测试Postfix对无效命令的处理。
# Requires Postfix-2.7+.
smtpd_command_filter = pcre:/etc/postfix/command_filter.pcre

# HELO restriction
# HELO限制
smtpd_helo_required = yes
smtpd_helo_restrictions =
    permit_mynetworks
    permit_sasl_authenticated
    check_helo_access pcre:/etc/postfix/helo_access.pcre
    reject_non_fqdn_helo_hostname
    reject_unknown_helo_hostname

# Sender restrictions
# 发件人限制
smtpd_sender_restrictions =
    reject_non_fqdn_sender
    reject_unlisted_sender
    permit_mynetworks
    permit_sasl_authenticated
    check_sender_access pcre:/etc/postfix/sender_access.pcre
    reject_unknown_sender_domain

# Recipient restrictions
# 收件人限制
smtpd_recipient_restrictions =
    reject_non_fqdn_recipient
    reject_unlisted_recipient
    check_policy_service inet:127.0.0.1:7777
    permit_mynetworks
    permit_sasl_authenticated
    reject_unauth_destination
    check_policy_service inet:127.0.0.1:12340

# END-OF-MESSAGE restrictions
# END-OF-MESSAGE限制
smtpd_end_of_data_restrictions =
    check_policy_service inet:127.0.0.1:7777

# Data restrictions
# 数据限制
smtpd_data_restrictions = reject_unauth_pipelining

# SRS (Sender Rewriting Scheme) support
# SRS(发件人重写方案)
#sender_canonical_maps = tcp:127.0.0.1:7778
#sender_canonical_classes = envelope_sender
#recipient_canonical_maps = tcp:127.0.0.1:7779
#recipient_canonical_classes= envelope_recipient,header_recipient

proxy_read_maps = $canonical_maps $lmtp_generic_maps $local_recipient_maps $mydestination $mynetworks $recipient_bcc_maps $recipient_canonical_maps $relay_domains $relay_recipient_maps $rel
ocated_maps $sender_bcc_maps $sender_canonical_maps $smtp_generic_maps $smtpd_sender_login_maps $transport_maps $virtual_alias_domains $virtual_alias_maps $virtual_mailbox_domains $virtual_
mailbox_maps $smtpd_sender_restrictions $sender_dependent_relayhost_maps

# Avoid duplicate recipient messages. Default is 'yes'.
# 避免重复的收件人消息。默认值为“yes”。
enable_original_recipient = no

# Virtual support.
# 支持虚拟账号
virtual_minimum_uid = 2000
virtual_uid_maps = static:2000
virtual_gid_maps = static:2000
virtual_mailbox_base = /var/vmail

# Do not set virtual_alias_domains.
virtual_alias_domains =

#
# Enable SASL authentication on port 25 and force TLS-encrypted SASL authentication.
# 在端口25上启用SASL身份验证,并强制TLS加密的SASL身份验证。
# WARNING: NOT RECOMMENDED to enable smtp auth on port 25, all end users should
#          be forced to submit email through port 587 instead.
# 警告:不建议在端口25上启用smtp身份验证,应强制所有最终用户通过端口587提交电子邮件。
# 实际操作中如果将以下三行屏蔽,outlook设置会比较麻烦。但是foxmail似乎不受影响。
#smtpd_sasl_auth_enable = yes
#smtpd_sasl_security_options = noanonymous
#smtpd_tls_auth_only = yes

# hostname
myhostname = mail.abc.org
myorigin = mail.abc.org
mydomain = mail.abc.org

# trusted SMTP clients which are allowed to relay mail through Postfix.
# 允许通过postfix中继邮件的受信任SMTP客户端。
# Note: additional IP addresses/networks listed in mynetworks should be listed
#       in iRedAPD setting 'MYNETWORKS' (in `/opt/iredapd/settings.py`) too.
#       for example:
#
#       MYNETWORKS = ['xx.xx.xx.xx', 'xx.xx.xx.0/24', ...]
#
mynetworks = 127.0.0.1 [::1]

# Accepted local emails
# 接受的本地电子邮件
mydestination = $myhostname, localhost, localhost.localdomain

alias_maps = hash:/etc/postfix/aliases
alias_database = hash:/etc/postfix/aliases

# Default message_size_limit.
# 默认邮件大小限制(15MB)
message_size_limit = 15728640

# The set of characters that can separate a user name from its extension
# (example: user+foo), or a .forward file name from its extension (example:
# .forward+foo).
# 可以将用户名与其扩展名(例如:user+foo),或者.forward文件名与其扩展名分离的字符集(例如:.forward+foo)。
# Postfix 2.11 and later supports multiple characters.
recipient_delimiter = +

# The time after which the sender receives a copy of the message headers of
# mail that is still queued. Default setting is disabled (0h) by Postfix.
# 发件人收到仍在排队的邮件的邮件头副本的时间。默认禁用(0h)
#delay_warning_time = 1h

# Do not display the name of the recipient table in the "User unknown" responses.
# 不要在“User unknown”响应中显示收件人表的名称。
# The extra detail makes trouble shooting easier but also reveals information
# that is nobody elses business.
# 额外的细节使故障排除变得更容易,但也揭示了与其他人无关的信息。
show_user_unknown_table_name = no

# compatibility_level,兼容性级别。
# 从Postfix版本3.6开始,兼容性级别是引入上次不兼容更改的Postfix版本。
# 级别格式为major.minor.patch,其中patch通常省略,默认为零。
# 早期的兼容性级别为0、1和2。
# 也可以使用<level或<=level,但不建议。
compatibility_level = 2

#
# Lookup virtual mail accounts
# 查找虚拟邮箱账号
transport_maps =
    proxy:mysql:/etc/postfix/mysql/transport_maps_user.cf
    proxy:mysql:/etc/postfix/mysql/transport_maps_maillist.cf
    proxy:mysql:/etc/postfix/mysql/transport_maps_domain.cf

sender_dependent_relayhost_maps =
    proxy:mysql:/etc/postfix/mysql/sender_dependent_relayhost_maps.cf

# Lookup table with the SASL login names that own the sender (MAIL FROM) addresses.
# 包含拥有发件人(邮件发件人)地址的SASL登录名的查找表。
smtpd_sender_login_maps =
    proxy:mysql:/etc/postfix/mysql/sender_login_maps.cf

virtual_mailbox_domains =
    proxy:mysql:/etc/postfix/mysql/virtual_mailbox_domains.cf

relay_domains =
    $mydestination
    proxy:mysql:/etc/postfix/mysql/relay_domains.cf

virtual_mailbox_maps =
    proxy:mysql:/etc/postfix/mysql/virtual_mailbox_maps.cf

virtual_alias_maps =
    proxy:mysql:/etc/postfix/mysql/virtual_alias_maps.cf
    proxy:mysql:/etc/postfix/mysql/domain_alias_maps.cf
    proxy:mysql:/etc/postfix/mysql/catchall_maps.cf
    proxy:mysql:/etc/postfix/mysql/domain_alias_catchall_maps.cf

sender_bcc_maps =
    proxy:mysql:/etc/postfix/mysql/sender_bcc_maps_user.cf
    proxy:mysql:/etc/postfix/mysql/sender_bcc_maps_domain.cf

recipient_bcc_maps =
    proxy:mysql:/etc/postfix/mysql/recipient_bcc_maps_user.cf
    proxy:mysql:/etc/postfix/mysql/recipient_bcc_maps_domain.cf

#
# Postscreen
# 僵尸拦截器
# 当远程SMTP客户端在postscreen_greet_wait参数指定的时间内(压力下默认2秒,否则默认6秒)在轮到它之前发言时,postscreen(8)所采取的操作。
# 指定以下选项之一:ignore(默认)、enforce、drop(立即中断链接,反馈代码521)
postscreen_greet_action = drop
# 3.6版之后改为postscreen_denylist_action,远程SMTP客户端在黑名单(postscreen_access_list)内就立即中断
postscreen_blacklist_action = drop
postscreen_dnsbl_action = drop
postscreen_dnsbl_threshold = 2

# Attention:
#   - zen.spamhaus.org free tire has 3 limits
#     (https://www.spamhaus.org/organization/dnsblusage/):
# 注意,zen.spamhaus.org仅在满足以下三条限制时可以自由使用:
#     1) Your use of the Spamhaus DNSBLs is non-commercial*, and
#        非商业
#     2) Your email traffic is less than 100,000 SMTP connections per day, and
#        每天SMTP连接数小于10万
#     3) Your DNSBL query volume is less than 300,000 queries per day.
#        每天DNSBL请求数小于30万
#
#   - FAQ: "Your DNSBL blocks nothing at all!"
#     https://www.spamhaus.org/faq/section/DNSBL%20Usage#261
#
# It's strongly recommended to use a local DNS server for cache.
# 强烈建议使用本地DNS服务器作为缓存
postscreen_dnsbl_sites =
    zen.spamhaus.org=127.0.0.[2..11]*3
    b.barracudacentral.org=127.0.0.2*2

postscreen_dnsbl_reply_map = texthash:/etc/postfix/postscreen_dnsbl_reply
postscreen_access_list = permit_mynetworks cidr:/etc/postfix/postscreen_access.cidr

# Require Postfix-2.11+
postscreen_dnsbl_whitelist_threshold = -2

#
# Dovecot SASL support.
#
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/dovecot-auth
# 官网资料说默认值为virutal
virtual_transport = dovecot
# 下面这个没找到
dovecot_destination_recipient_limit = 1

#
# mlmmj - mailing list manager
# 邮件列表管理器(官网资料未找到)
mlmmj_destination_recipient_limit = 1

#
# Amavisd + SpamAssassin + ClamAV
#
content_filter = smtp-amavis:[127.0.0.1]:10024

# Concurrency per recipient limit.
# 每个收件人的并发限制
smtp-amavis_destination_recipient_limit = 1

Debian下iRedMail的master.cf:

mailman@mail:/etc/postfix$ more master.cf
#
# Postfix master process configuration file.  For details on the format
# of the file, see the master(5) manual page (command: "man 5 master" or
# on-line: http://www.postfix.org/master.5.html).
#
# Do not forget to execute "postfix reload" after editing this file.
# 修改后需运行postfix reload命令使变更生效
# ==========================================================================
# service type  private unpriv  chroot  wakeup  maxproc command + args
# 服务     类型  私有     非特权的 改变根目录 唤醒   最大线程数 命令+参数
#               (yes)   (yes)   (no)    (never) (100)
# ==========================================================================
smtp      inet  n       -       y       -       1       postscreen
smtpd     pass  -       -       y       -       -       smtpd
dnsblog   unix  -       -       y       -       0       dnsblog
tlsproxy  unix  -       -       y       -       0       tlsproxy
#submission inet n       -       y       -       -       smtpd
#  -o syslog_name=postfix/submission
#  -o smtpd_tls_security_level=encrypt
#  -o smtpd_sasl_auth_enable=yes
#  -o smtpd_tls_auth_only=yes
#  -o smtpd_reject_unlisted_recipient=no
#  -o smtpd_client_restrictions=$mua_client_restrictions
#  -o smtpd_helo_restrictions=$mua_helo_restrictions
#  -o smtpd_sender_restrictions=$mua_sender_restrictions
#  -o smtpd_recipient_restrictions=
#  -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
#  -o milter_macro_daemon_name=ORIGINATING
#smtps     inet  n       -       y       -       -       smtpd
#  -o syslog_name=postfix/smtps
#  -o smtpd_tls_wrappermode=yes
#  -o smtpd_sasl_auth_enable=yes
#  -o smtpd_reject_unlisted_recipient=no
#  -o smtpd_client_restrictions=$mua_client_restrictions
#  -o smtpd_helo_restrictions=$mua_helo_restrictions
#  -o smtpd_sender_restrictions=$mua_sender_restrictions
#  -o smtpd_recipient_restrictions=
#  -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
#  -o milter_macro_daemon_name=ORIGINATING
#628       inet  n       -       y       -       -       qmqpd
#smtp       inet  n       -       -       -       -       smtpd
pickup     unix  n       -       n       60      1       pickup
    -o content_filter=smtp-amavis:[127.0.0.1]:10026
cleanup    unix  n       -       n       -       0       cleanup
#qmgr     unix  n       -       n       300     1       oqmgr
qmgr       unix  n       -       n       300     1       qmgr
tlsmgr     unix  -       -       n       1000?   1       tlsmgr
rewrite    unix  -       -       n       -       -       trivial-rewrite
bounce     unix  -       -       n       -       0       bounce
defer      unix  -       -       n       -       0       bounce
trace      unix  -       -       n       -       0       bounce
verify     unix  -       -       n       -       1       verify
flush      unix  n       -       n       1000?   0       flush
proxymap   unix  -       -       n       -       -       proxymap
proxywrite unix  -       -       n       -       1       proxymap
smtp       unix  -       -       n       -       -       smtp
#       -o smtp_helo_timeout=5 -o smtp_connect_timeout=5
relay      unix  -       -       n       -       -       smtp
    -o syslog_name=postfix/$service_name
showq      unix  n       -       n       -       -       showq
error      unix  -       -       n       -       -       error
retry      unix  -       -       n       -       -       error
discard    unix  -       -       n       -       -       discard
local      unix  -       n       n       -       -       local
virtual    unix  -       n       n       -       -       virtual
lmtp       unix  -       -       n       -       -       lmtp
anvil      unix  -       -       n       -       1       anvil
scache     unix  -       -       n       -       1       scache
#
# ====================================================================
# Interfaces to non-Postfix software. Be sure to examine the manual
# pages of the non-Postfix software to find out what options it wants.
#
# Many of the following services use the Postfix pipe(8) delivery
# agent.  See the pipe(8) man page for information about ${recipient}
# and other message envelope options.
# ====================================================================
#
# maildrop. See the Postfix MAILDROP_README file for details.
# Also specify in main.cf: maildrop_destination_recipient_limit=1
#
postlog    unix-dgram n  -       n       -       1       postlogd
#
# ====================================================================
#
# Recent Cyrus versions can use the existing "lmtp" master.cf entry.
#
# Specify in cyrus.conf:
#   lmtp    cmd="lmtpd -a" listen="localhost:lmtp" proto=tcp4
#
# Specify in main.cf one or more of the following:
#  mailbox_transport = lmtp:inet:localhost
#  virtual_transport = lmtp:inet:localhost
#
# ====================================================================
#
# Cyrus 2.1.5 (Amos Gouaux)
# Also specify in main.cf: cyrus_destination_recipient_limit=1
#
#cyrus     unix  -       n       n       -       -       pipe
#  flags=DRX user=cyrus argv=/cyrus/bin/deliver -e -r ${sender} -m ${extension} ${user}
#
# ====================================================================
# Old example of delivery via Cyrus.
#
#old-cyrus unix  -       n       n       -       -       pipe
#  flags=R user=cyrus argv=/cyrus/bin/deliver -e -m ${extension} ${user}
#
# ====================================================================
#
# See the Postfix UUCP_README file for configuration details.
#
maildrop   unix  -       n       n       -       -       pipe flags=DRXhu
    user=vmail argv=/usr/bin/maildrop -d ${recipient}
#
# Other external delivery methods.
#
uucp       unix  -       n       n       -       -       pipe flags=Fqhu
    user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
ifmail     unix  -       n       n       -       -       pipe flags=F user=ftn
    argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
bsmtp      unix  -       n       n       -       -       pipe flags=Fq.
    user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient
scalemail-backend unix - n       n       -       2       pipe flags=R
    user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop}
    ${user} ${extension}
mailman    unix  -       n       n       -       -       pipe flags=FRX
    user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py ${nexthop}
    ${user}
# Submission, port 587, force TLS connection.
# 开放587端口,强制TLS连接
submission inet n       -       n       -       -       smtpd
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
  -o content_filter=smtp-amavis:[127.0.0.1]:10026

# smtps, port 465, force SSL connection.
# 开放465端口,强制SSL连接
465 inet  n       -       n       -       -       smtpd
  -o syslog_name=postfix/smtps
  -o smtpd_tls_wrappermode=yes
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
  -o content_filter=smtp-amavis:[127.0.0.1]:10026

# Use dovecot's `deliver` program as LDA.
# 使用dovecot的‘deliver’程序作为LDA
dovecot unix    -       n       n       -       -      pipe
    flags=DRh user=vmail:vmail argv=/usr/lib/dovecot/deliver -f ${sender} -d ${user}@${domain} -m ${extension}

# mlmmj - mailing list manager
# ${nexthop} is '%d/%u' in transport ('mlmmj:%d/%u')
mlmmj   unix  -       n       n       -       -       pipe
    flags=ORhu user=mlmmj:mlmmj argv=/usr/bin/mlmmj-amime-receive -L /var/vmail/mlmmj/${nexthop}

# Amavisd integration.
# amavixd集成
smtp-amavis unix -  -   n   -   4  smtp
    -o syslog_name=postfix/amavis
    -o smtp_data_done_timeout=1200
    -o smtp_send_xforward_command=yes
    -o disable_dns_lookups=yes
    -o max_use=20

# smtp port used by Amavisd to re-inject scanned email back to Postfix
# smtp端口,用于amvaisd返回扫描过的邮件到postfix
127.0.0.1:10025 inet n  -   n   -   -  smtpd
    -o syslog_name=postfix/10025
    -o content_filter=
    -o mynetworks_style=host
    -o mynetworks=127.0.0.0/8
    -o local_recipient_maps=
    -o relay_recipient_maps=
    -o strict_rfc821_envelopes=yes
    -o smtp_tls_security_level=none
    -o smtpd_tls_security_level=none
    -o smtpd_restriction_classes=
    -o smtpd_delay_reject=no
    -o smtpd_client_restrictions=permit_mynetworks,reject
    -o smtpd_helo_restrictions=
    -o smtpd_sender_restrictions=
    -o smtpd_recipient_restrictions=permit_mynetworks,reject
    -o smtpd_end_of_data_restrictions=
    -o smtpd_error_sleep_time=0
    -o smtpd_soft_error_limit=1001
    -o smtpd_hard_error_limit=1000
    -o smtpd_client_connection_count_limit=0
    -o smtpd_client_connection_rate_limit=0
    -o receive_override_options=no_header_body_checks,no_unknown_recipient_checks,no_address_mappings

# smtp port used by mlmmj to re-inject scanned email back to Postfix, with
# address mapping support
# smtp端口,用于mlmmj返回扫描过的邮件到postfix,支持地址映射
127.0.0.1:10028 inet n  -   n   -   -  smtpd
    -o syslog_name=postfix/10028
    -o content_filter=
    -o mynetworks_style=host
    -o mynetworks=127.0.0.0/8
    -o local_recipient_maps=
    -o relay_recipient_maps=
    -o strict_rfc821_envelopes=yes
    -o smtp_tls_security_level=none
    -o smtpd_tls_security_level=none
    -o smtpd_restriction_classes=
    -o smtpd_delay_reject=no
    -o smtpd_client_restrictions=permit_mynetworks,reject
    -o smtpd_helo_restrictions=
    -o smtpd_sender_restrictions=
    -o smtpd_recipient_restrictions=permit_mynetworks,reject
    -o smtpd_end_of_data_restrictions=
    -o smtpd_error_sleep_time=0
    -o smtpd_soft_error_limit=1001
    -o smtpd_hard_error_limit=1000
    -o smtpd_client_connection_count_limit=0
    -o smtpd_client_connection_rate_limit=0
    -o receive_override_options=no_header_body_checks,no_unknown_recipient_checks

防病毒及垃圾邮件

对clamav进行配置

FreeBSD下无需修改,debian下需要修改/usr/local/etc/clamd.conf文件,追加一句:
AllowSupplementaryGroups true
然后重启clamav服务。

对amavisd进行配置

修改/usr/local/etc/amavisd.conf确定有如下行:
# @bypass_virus_checks_maps = (1);  # controls running of anti-virus code
# @bypass_spam_checks_maps  = (1);  # controls running of anti-spam code
# $bypass_decode_parts = 1;         # controls running of decoders&dearchivers
$daemon_user  = 'vscan';     # (no default;  customary: vscan or amavis), -u
$daemon_group = 'vscan';     # (no default;  customary: vscan or amavis), -g
$mydomain = 'example.com';   # a convenient default for other settings (此处需要根据实际情况修改)
$MYHOME = '/var/amavis';   # a convenient default for other settings, -H (去掉前面的井号)
@local_domains_maps = ( [".$mydomain","myotherdomain.net"] );  # list of all local domains(可以有多个域名,域名用双引号括起来,域名之间用逗号分隔)
$myhostname = 'host.example.com';  # must be a fully-qualified domain name! (去掉前面的井号,并根据实际情况修改)
配置文件里面引出两个邮箱:virusalert\@mydomain(用于接收并病毒邮件)、spam.police\@mydomain(用于处理垃圾邮件),需要为它们创建虚拟账号。
再修改/usr/local/etc/amavisd.conf,将以下行取消注释:
['ClamAV-clamd', \&ask_daemon, ["CONTSCAN {}\n", "/var/run/clamav/clamd.sock"], qr/\bOK$/m, qr/\bFOUND$/m, qr/^.*?: (?!Infected Archive)(.*) FOUND$/m ],
如果是在jail中运行邮件系统,还需要在/usr/local/etc/amavisd.conf中加入ACL:
@inet_acl = qw(192.168.0.111 127.0.0.1 [::1]);

webmail

初始化配置

首先修改nginx配置文件/usr/local/etc/nginx/nginx.conf,以指向roundcube的目录。并重启nginx。
打开浏览器,地址栏输入http://192.168.0.18/installer 进入配置roundcube配置页面。
正常来讲,php及必要的插件已经有了,还有一些可选插件需要安装:
cURL、LDAP、GD、Imagick
安装这些插件:
pkg install php80-curl php80-ldap php80-gd php80-pecl-imagick
重启php-fpm,然后刷新roundcube安装页面,继续安装过程。
配置roundcube连接数据库时,数据库服务器地址不能用localhost,要用127.0.0.1

完成以上设置后点击CREATE CONFIG按钮,会在页面上出现一个代码框,可以将其下载到本地,或保存到服务器的/tmp/目录下。
也可以直接在服务器的/usr/local/www/roundcube/config/下创建config.inc.php文件,并将这些代码复制到该文件中。
然后按CONTINUE按钮,进入TestConfig页面,如果可以正常连接数据库,则会自动创建对应的表。
若遇到错误提示:
Mimetype to file extension mapping: NOT OK
可以修改/usr/local/etc/www/roundcube/confing/config.inc.php,在最后加入一行:
$config['mime_types']='/usr/local/www/roundcube/config/mime.types';
然后在/usr/local/etc/www/roundcube/confing/目录下执行:
fetch http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types

关于password插件

修改/usr/local/www/roundcube/plugins/password/config.inc.php中以下参数:
$config['password_driver'] = 'dovecot_passwdfile_my';  //使用dovecot_passwdfile驱动
$config['password_algorithm'] = 'dovecot';
$config['password_dovecotpw'] = '/usr/local/bin/doveadm pw'; // for dovecot-2.x
$config['password_dovecotpw_method'] = 'BLF-CRYPT';  //dovecot默认的密码加密方式
$config['password_dovecotpw_with_method'] = true;
$config['password_dovecot_passwdfile_path'] = '/var/vmail/user-passwd'; //此处对应账号密码文件的完整路径
自带的dovecot_passwdfile插件配置文件有问题,但是如果直接修改它的话,软件更新时会被冲掉,所以要创建自己的driver文件:
# cd /usr/local/www/roundcube/plugins/password/dirvers/
# cp dovecot_passwdfile.php dovecot_passwdfile_my.php
修改它,将
class rcube_dovecot_passwdfile_password
改为
class rcube_dovecot_passwdfile_password_my
然后将
$line = "$username:$password" . substr($line, $pos);
改为:
$line = "$username:$password";

fail2ban

复制/usr/local/etc/fail2ban/action.d/ipfw.conf为ipfw-ssh.conf,并将actionban和actionunban的值改为以下:
actionban = ipfw table 1 add <ip>
actionunban = ipfw table 1 delete <ip>
以上两句原本分别为:
actionban = ipfw add  tcp from  to  
actionunban = ipfw delete `ipfw list | grep -i "[^0-9][^0-9]" | awk '{print $1;}'`
第一句在ipfw中加入对某个IP的拦截,第二句从ipfw规则中删除指定IP。

修改/usr/local/etc/fail2ban/jail.conf文件中以下参数的值:
bantime 10h
findtime = 10h
在/usr/local/etc/fail2ban/jail.d中分别创建ssh.conf、dovecot.conf、postfix.conf、roundcube.conf文件,内容大致如下:
[ssh-ipfw]
enabled=true
filter=bsd-sshd             dovecot对应dovecot,postfix对应postfix,roundcube对应roundcube-auth
action=ipfw-ssh             也可以用bsd-ipfw
logpath=/var/log/auth.log   dovecot、postfix和roundcube对应/var/log/maillog
maxretry=3
修改过滤器/usr/local/etc/fail2ban/filter.d/postfix.conf文件。 该过滤器依照严格程度分为以下几种模式: 若需要更改模式,只需更改此文件中mode项的值,例如:
mode = aggressive
将使用最严格的规则。
在/usr/local/etc/fail2ban/jail.conf文件中添加例外规则:
ignoreip = 127.0.0.1/8 ::1 192.168.0.0/20 202.96.222.41
多个IP、CIDR(俗称IP段)、DNS主机可以用空格和逗号分隔。
使用以下命令查看每个jail里的状况:
# fail2ban-client status ssh-ipfw
使用以下命令查看当前被阻止的IP:
# ipfw table 1 list
手动封掉指定ip:
# fail2ban-client set ssh-ipfw banip 192.168.0.33
手动解封指定ip:
# fail2ban-client unban 192.168.0.33