Exim
Exim 是一个通用的邮件传输代理。本文建立在邮件服务器之上。虽然Exim Wiki提供了一些关于特定用例的实用操作指南,但同时也提供了所有配置选项的详细描述。
安装
基本配置
Exim 附带一个庞大的默认配置文件,位于 /etc/mail/exim.conf
。其中的许多选项在常规用例中是不必要的。
配置可以在包含多个章节的单个文件中完成。Exim 的配置分为多个不同的部分。通用选项设置必须始终出现在任何其他部分之前。其他部分都是可选的,并且可以以任何顺序出现。除了通用选项部分之外,每个部分都以单词 “begin” 开头,后跟至少一个文字空格,以及该部分的名称。关于 exim 运行时配置的其他一般性评论,请参考官方文档的此链接。
以下是一个非常基本的配置,它提供:本地投递给系统用户,Mbox(也称为传统 BSD 邮箱)格式,以及授权中继到 MX 主机。描述基于在主机 “hostname.mydomain.tld” 上服务的域 “mydomain.tld”。强烈建议在使用下面给出的文档之前查阅官方文档。
主要参数
必需的通用选项章节包含一些基本选项。仅使用这些选项将打开端口以进行连接,但仍然不会接受任何邮件,也不会中继到任何地方。
# be the responsible mail host for hostname.mydomain.tld (@) & mydomain.tld domainlist local_domains = @ : mydomain.tld # we don't relay. Not for foreign domains nor for a single host domainlist relay_to_domains = hostlist relay_from_hosts = # serve the on all used ports daemon_smtp_ports = 25 : 465 : 587 # do a reverse name lookup for all incoming connections host_lookup = * # Logging: log all events, add syslog to logging path & avoid double entries log_selector = +all log_file_path = : syslog syslog_duplication = false # undeliverables: discard bounce messages after 2d and all others after 7 d ignore_bounce_errors_after = 2d timeout_frozen_after = 7d
TLS,安全 & 身份验证
要获取证书,请参阅 OpenSSL#用法。
以下选项的第一部分仍然是 Exim 中第一个配置部分的一部分。从 “begin authenticators” 开始,此处建议配置的第一个特殊部分开始。稍后将有其他部分。下面定义了一些非常基本的安全相关选项,设置了 TLS,并引入了使用用户密码查找的纯文本身份验证器。
# actually not required: it's hard coded - anyway: no mail delivery to root never_users = root # don't show the exim version to everyone. Actually not even show the name. smtp_banner = $smtp_active_hostname ESMTP $tod_full # STARTTLS is offered to everyone tls_advertise_hosts = * tls_certificate = /path/to/exim/only/fullchain.pem tls_privatekey = /path/to/exim/only/privkey.pem # use all ciphers on port 25, use only good ciphers on port 587 tls_require_ciphers = ${if =={$received_port}{25} \ {DEFAULT} {HIGH:!MD5:!SHA1:!SHA2}} # traffic on port 465 always uses TLS tls_on_connect_ports = 465 # special sections always start with a "begin" begin authenticators PLAIN: # authentication protocol is plain text driver = plaintext # authentication is offered as plain text public_name = PLAIN server_prompts = : # authentication is successful, if the password provided ($auth3) # equals the password found in a lookup file for user ($auth2) server_condition = ${if eq{$auth3}{${lookup{$auth2}dbm{/etc/authpwd}}}} server_set_id = $auth2 # only offer plain text authentication after TLS is been negotiated server_advertise_condition = ${if def:tls_in_cipher}
exim
加载证书文件。虽然使用这样的用户运行面向互联网的进程是好的,但将私钥的访问权限授予这样的用户有点奇怪。如果您的服务器提供多种用途(例如 HTTP、IMAP、SMTP),并具有多个 DNS 别名(CNAME 或指向单个 IP 的多个名称),则请求多个证书可能是明智之举。如果 Exim 私钥丢失,则损坏仅限于 SMTP。路由,传输 & 重试
对于消息的每个收件人,路由执行如下:路由器按照路由部分中给出的顺序进行测试。对于每个路由器,条件可能适用(例如 domains = ! +local_domains
)。仅当所有条件都适用时,消息才会被移交给定义的传输(例如 transport = smtp
)。如果传输失败或未满足路由器的所有条件,则测试下一个路由器。
begin routers # that's the relay router dnslookup: # the router type driver = dnslookup # the domains served on this router: not the local domain domains = ! +local_domains # the transport to be used (see transport section below) transport = remote_delivery # localhost is to be ignored if dns gives such result ignore_target_hosts = <; 0.0.0.0 ; 127.0.0.0/8 ; ::1 # a router list is processed until matched and successful transported. # if transport fails, we don't want the next router to be used no_more # local delivery localuser: # the transport type - we accept the mail locally driver = accept # this router serves only our domains domains = +local_domains # use transport named local_delivery transport = local_delivery # in case local delivery fails cannot_route_message = Unknown local user begin transports remote_delivery: driver = smtp local_delivery: #deliver to a local mailbox driver = appendfile file = /var/mail/$local_part # if routing or transport fails, try again after this (default) ruleset begin retry # Address or Domain Error Retries # ----------------- ----- ------- * * F,2h,15m; G,16h,1h,1.5; F,4d,6h
使用 manualroute
如果您想改用 manualroute,请注释掉 dnslookup 块并添加 smarthost 块。
#dnslookup: # the router type # driver = dnslookup # the domains served on this router: not the local domain # domains = ! +local_domains # the transport to be used (see transport section below) # transport = remote_delivery # localhost is to be ignored if dns gives such result # ignore_target_hosts = <; 0.0.0.0 ; 127.0.0.0/8 ; ::1 # a router list is processed until matched and successful transported. # if transport fails, we don't want the next router to be used # no_more smarthost: driver = manualroute domains = !+local_domains transport = remote_delivery route_list = * smtp.myisp.com # change to the desired smtp server ignore_target_hosts = <; 0.0.0.0 ; 127.0.0.0/8 ; ::1
ACL:访问控制列表
访问控制列表是 Exim 的核心。它们是基本检查所必需的,并且可以用于复杂的消息处理。一般来说,Exim 中的整体消息处理是
connection > (authentication >) ACL > routing > transport
重要的是要注意,来自经过身份验证的客户端的消息(默认情况下)与来自其他邮件服务器的消息使用相同的 ACL。Exim 知道完整的不同 ACL 集合。要选择正确的 ACL 集,需要具备良好的 SMTP 协议知识。
acl_smtp_connect > acl_smtp_helo > ... > acl_smtp_rcpt > ... > acl_smtp_data > ...
对于基本设置,两个 ACL 是强制性的:acl_smtp_rcpt 和 acl_smtp_data。这些默认设置为拒绝,而所有其他默认设置为接受。下面的示例仅阻止成为开放中继。此设置存在多个安全漏洞(例如,所有经过身份验证的用户都可以使用任何邮件地址)。如果添加到现有配置,则必须在任何其他特殊部分之前添加(即在任何现有的 “begin” 之前)。
# use this ACL after SMTP RCPT TO: is received acl_smtp_rcpt = basic_acl_rcpt # use this ACL after SMTP DATA is finished, i.e. all data has been received acl_smtp_data = basic_acl_data begin acl basic_acl_rcpt: # accept all messages for which I am the receiving mail host accept domains = +local_domains # accept all messages from authenticated clients accept authenticated = * # deny all other messages (i.e. messages to be relayed from unauthorized # clients) deny message = "we are not an open relay" basic_acl_data: # we have done all checks after RCPT already accept
隐藏机器名
如果您有笔记本电脑或智能主机配置中的机器,并且不希望机器的名称出现在外发电子邮件中,则必须启用 exim 的重写功能。
在重写部分中,您应该有类似这样的内容
*@machine.mydomain $1@mydomain
其中 machine
是您的笔记本电脑或 PC 的主机名,mydomain
是机器和外发邮件的域名。要仅重写发件人域名,请在行尾添加特殊标志 (F)。有关详细信息,请参阅上游文档
启动
启动/启用 exim.service
。
Dovecot LMTP 投递 & SASL 身份验证
本节描述了 Dovecot 的集成。假设 Dovecot & Exim 已经安装和配置。Dovecot 将用作 SASL 身份验证器和本地传输机制。为此,Dovecot 服务将按如下方式设置。
/etc/dovecot/conf.d/10-master.conf
service auth { unix_listener exim-auth { mode = 0600 user = exim group = exim } # Auth process is run as this user. user = $default_internal_user } service lmtp { # a unix socket is preferred of a local port communication unix_listener exim-lmtp { mode = 0600 group = exim user = exim } }
要在 TLS 保护的环境中使用 Dovecot SASL,请将以下身份验证器添加到 Exim。
/etc/mail/exim.conf - authenticators section
PLAIN: driver = dovecot public_name = PLAIN server_socket = /var/run/dovecot/exim-auth server_set_id = $auth1 server_advertise_condition = ${if def:tls_in_cipher}
可以重用现有的本地投递路由器。您可能需要考虑在路由器定义中添加 dsn_lasthop
。如果使用 DSN,Exim 将在此点假定消息的最终投递。在传输部分中,本地投递的传输必须替换为以下传输定义。
/etc/mail/exim.conf - transports section
local_delivery: driver = lmtp socket = /var/run/dovecot/exim-lmtp batch_max = 200
verify = recipient/callout=no_cache
将无法按预期工作,即,不存在的用户帐户不会引发失败。要完成针对 Dovecot 的收件人检查,您必须将上面的驱动程序替换为driver = smtp protocol = lmtp port = 2525
主机在路由器中指定,而不是在传输中指定。因此,路由器必须看起来像
lmtp_router: driver = manualroute domains = +local_domains transport = local_delivery route_list = * 127.0.0.1 byname此外,您的 Dovecot lmtp 服务必须进行相应的调整。例如:这是一个Git 提交,修复了完全相同的问题。
由于 Dovecot 配置为为 exim 用户提供 unix 套接字,因此您可以通过在主配置部分中添加以下行来加强安全性。
/etc/mail/exim.conf - main section
# don't deliver being root, drop privileges to exim user deliver_drop_privilege = true
使用 Gmail 作为智能主机
在 exim conf 文件的开头,您必须使用以下命令启用 TLS
tls_advertise_hosts = +local_network : *.gmail.com
或向所有主机声明 tls
tls_advertise_hosts = *
有关 TLS 的更多信息,请参见 exim 文档。
在 dnslookup 路由器之前或代替它添加路由器
gmail_route: driver = manualroute transport = gmail_relay route_list = * smtp.gmail.com
添加传输
gmail_relay: driver = smtp port = 587 tls_verify_certificates = /etc/ssl/certs/ca-certificates.crt # this forces host verification. tls_verify_hosts = smtp.gmail.com hosts_require_auth = <; $host_address hosts_require_tls = <; $host_address
由于主机验证,您的 exim 日志可能包含
SSL verify error: certificate name mismatch: "/C=US/ST=California/L=Mountain View/O=Google Inc/CN=smtp.gmail.com"
但这不会影响邮件传递,可以忽略。添加身份验证器(将 myaccount@gmail.com 和 mypassword 替换为您自己的帐户详细信息)
gmail_login: driver = plaintext public_name = LOGIN hide client_send = : myaccount@gmail.com : mypassword
$host_address
用于 hosts_require_auth
和 hosts_require_tls
而不是 smtp.gmail.com,以避免偶尔出现的 530 5.5.1 Authentication Required 错误。这些错误是由 smtp.gmail.com 的 DNS 查询中不断变化的 IP 地址引起的。$host_address
将扩展为 gmail_route
路由器解析的特定 IP 地址。
为了增加安全性,请使用应用专用密码。这也适用于 Google Apps 帐户。
加固
速率限制
安全漏洞时有发生。如果您没有任何提交本地邮件的服务(从端口上的 localhost 接收邮件不被视为本地提交),请完全禁用本地提交。为此,请在 main 部分中添加 acl_not_smtp = acl_local
,并在 acl 部分中添加以下简单 ACL。
/etc/mail/exim.conf - acl section
acl_local: deny log_message = AL01: Local submission denied.
如果需要本地提交,请考虑对其施加速率限制。为此,请在 main 部分中添加 acl_not_smtp = acl_local
,并在 acl 部分中添加以下 ACL。它施加了 2 个速率限制:1 分钟内 20 封邮件和 10 分钟内 30 封邮件。这样,即使可能出现本地提交的警报突发
/etc/mail/exim.conf - acl section
acl_local: # apply a limit of 30 mails to the administrator for alerts submitted # by local services deny ratelimit = 30 / 1m / strict recipients = admin@mydomain.tld : root@hostname.mydomain.tld log_message = AL01: Sender rate limit for local submission \ exceeded: $sender_rate / $sender_rate_period. # apply a burst limit of 3 mails per minute to everyone else deny ratelimit = 3 / 1m / strict !recipients = admin@mydomain.tld : root@hostname.mydomain.tld log_message = AL02: Sender rate limit for local submission \ exceeded: $sender_rate / $sender_rate_period. # apply a regular limit of 10 mails per 30 minutes to everyone else deny ratelimit = 10 / 30m / strict !recipients = admin@mydomain.tld : root@hostname.mydomain.tld log_message = AL03: Sender rate limit for local submission \ exceeded: $sender_rate / $sender_rate_period. accept
故障排除
451 临时本地问题
如果您在测试 SMTP 时遇到 “451 Temporary Local Problem”,则可能是以 root 身份发送。默认情况下,Exim 不允许您以 root 身份发送。