跳转至内容

Exim

来自 ArchWiki

Exim 是一个多功能的邮件传输代理。本文建立在邮件服务器的基础上。虽然Exim wiki 提供了一些关于特定用例的有用指南,但有关所有配置选项的详细描述也可用。

安装

安装 exim 包。

基本配置

Exim 自带一个庞大的默认配置文件,位于 /etc/mail/exim.conf。其中许多选项在常规使用场景中并不需要。

配置可以包含在多个章节的单个文件中。Exim 的配置分为几个不同的部分。通用选项设置必须始终出现在其他任何部分之前。其他部分都是可选的,可以按任意顺序出现。除通用选项部分外,每个部分都以单词“begin”开头,后跟至少一个空格,然后是部分名称。关于 exim 运行时配置的其他通用注释可通过此链接指向的官方文档获得。

以下是一个非常基本的配置,它提供了:本地邮件传递到系统用户、Mbox(也称为传统 BSD 邮箱)格式,以及授权中继到 MX 主机。描述基于在主机“hostname.mydomain.tld”上服务的域名“mydomain.tld”。强烈建议在使用下面的给定文档之前查阅官方文档。

注意 此处显示的配置文件的设置顺序与软件包附带的默认配置有所不同。
警告 默认配置文件的权限为 0644。这意味着任何用户都可以读取。如果在此文件中保留敏感信息(如LDAP 凭据等),请根据需要更改此权限,也许改为 0640。

主要参数

必需的通用选项部分包含一些基本选项。仅使用这些选项将打开连接端口,但仍然不会接受或中继任何邮件。

# 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、安全与认证

本文章或章节需要扩充。

原因:将低权限用户访问私钥是否存在事实上的担忧?为什么 Exim 私钥会丢失?(在 Talk:Exim 中讨论)
警告 如果您部署了TLS,请务必遵循服务器端 TLS以防止漏洞。

获取证书,请参见 OpenSSL#Usage

以下选项的第一部分仍然是 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 在邮件处理过程中以低权限用户 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 认证

本文章或章节需要扩充。

原因:LMTP 是什么?(在 Talk:Exim 中讨论)

本节描述了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
注意 从 Exim 4.88 开始,lmtp 驱动程序有一个限制:在 ACL 中,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 服务必须相应调整[已失效链接 2025-08-15—HTTP 404]。例如:这是一个修复此确切问题的 Git commit

由于 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 配置文件开头,您必须使用以下命令启用 TLS:

tls_advertise_hosts = +local_network : *.gmail.com

或者向所有主机宣传 tls

tls_advertise_hosts = *

有关 TLS 的更多信息,请参阅Exim 文档

注意 以下内容必须放在配置文件相应的节中,例如,放在 begin authenticators 之后。

在 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_authhosts_require_tls,而不是 smtp.gmail.com,以避免偶尔出现 530 5.5.1 Authentication Required 错误。这些错误是由 smtp.gmail.com DNS 查询中的 IP 地址更改引起的。$host_address 将展开为 gmail_route 路由器解析到的特定 IP 地址。

为了提高安全性,请使用每个应用程序的密码。这同样适用于 Google Workspace 帐户。

加固

速率限制

安全漏洞时有发生。如果您没有任何提交本地邮件的服务(从 localhost 接收邮件不被视为本地提交),请完全禁用本地提交。通过在主节中添加 acl_not_smtp = acl_local 并将以下简单的 ACL 添加到 acl 节来实现。

/etc/mail/exim.conf - acl section
	acl_local:

		deny	log_message = AL01: Local submission denied.

如果需要本地提交,请考虑对其施加速率限制。通过在主节中添加 acl_not_smtp = acl_local 并将以下 ACL 添加到 acl 节来实现。它施加了 2 个速率限制:每分钟 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 用户身份发送。

参见

© . This site is unofficial and not affiliated with Arch Linux.

Content is available under GNU Free Documentation License 1.3 or later unless otherwise noted.