10
24
2024
1

为团队部署邮件服务

给服务器上的程序部署邮件服务十分简单,装个 Postfix 就搞定了。然而给人用的话就远远不够了。之所以要干这事,主要原因是之前使用的 Yandex 邮箱老出问题,丢邮件都算小事了,它还不让我登录 Web 界面,非要我填写我从未设置的密保问题的答案……

准备工作

要部署邮件服务,首先当然要有域名和服务器了。需要注意的是,最好使用可以设置 PTR 记录的服务器,有些邮件服务器会要求这个。

邮件传输代理

这是最重要的部分。邮件传输代理,简称 MTA,是监听 TCP 25 端口、与其它邮件服务器交互的服务程序。我最常用的是 Postfix,给服务器上的程序用的话,它相当简单易用。但是要给它配置上 IMAP 和 SMTP 登录服务、以便给人类使用的话,就很麻烦。好在之前听群友说过 maddy,不仅能收发邮件,还支持简单的 IMAP 服务。唯一的缺点是不支持通过 25 端口发送邮件——需要走 465 或者 587 端口,登录之后才能发件。它的账号系统也是独立于 UNIX 账号的,给程序使用需要额外的配置。

具体配置方面,首先是域名和 TLS 证书。我不知道为什么,它在分域名证书的选择上有些问题,最后我干脆全部用通配符证书解决了事。数据库我使用的是 PostgreSQL。要使用本地 peer 鉴权的话,需要把 host 的值设置为 PostgreSQL 监听套接字所在的目录,比如我是这样写的:

dsn "user=maddy host=/run/postgresql dbname=maddy sslmode=disable"

PostgreSQL 监听套接字所在目录是编译时确定的。maddy 是 Go 写的,并不使用 libpq,因此它无法自动确定这个目录在哪里,需要手动指定。

关于邮箱别名,可以使用文本文件配置,也可以使用数据库查询指定。别名功能可以用来实现简单的邮件列表功能——发往某一个地址的邮件会被分发到多个实际收件人的邮箱中。但是它不支持去重,也就是说,往包含自己的别名地址发送邮件,自己会额外收到一份。设置起来大概是这样子的:

table.chain local_rewrites {
    optional_step regexp "(.+)\+(.+)@(.+)" "$1@$3"
    optional_step static {
        entry postmaster postmaster@$(primary_domain)
    }
    optional_step file /etc/maddy/aliases
    step sql_query {
        driver postgres
        dsn "user=maddy host=/run/postgresql dbname=maddy sslmode=disable"                                                                                                                 
        lookup "SELECT mailname FROM mailusers.mailinfo WHERE $1 = ANY(alias) and new = false"
    }
}

哦对了,那个 postmaster 地址需要手动合并,不然就要每个域名创建一个账号了。在别名文件里写上 postmaster@host2: postmaster@host1 就行了。

maddy 会经常检查别名的修改时间然后自动重新加载,数据库查询当然是查出来是什么就是什么,所以还是比 Postfix 每次跑 postalias 命令要方便不少。

DNS 配置

邮件域名的 MX 记录当然要设置上的。邮件服务器 IP 的 PTR 记录也要设置到服务器的域名上(A / AAAA 记录指到服务器)。SPF 的记录也不能忘。DMARC 和 DKIM 的记录没那么重要,不过推荐按 maddy 的文档设置上。

我还给域名设置 imap、imaps 和 submission 的 SRV 记录,但似乎客户端们并不使用它们。

这些设置好之后就可以去 https://email-security-scans.org/ 发测试邮件啦。

反垃圾

maddy 内建对 rspamd 的支持,所以就用它好了。直接在 smtpcheck 节里写上 rspamd 就好了。rspamd 跟着官方教程走,也基本不需要什么特别的设置,就是官方给的 nginx 配置有些坑人。我是这样设置的:

    location /rspamd/ {
            alias /usr/share/rspamd/www/;
            expires 30d;
            index index.html;
            try_files $uri $uri/ @proxy;
    }
    location @proxy {
            rewrite ^/rspamd/(.*)$ /$1 break;
            proxy_pass  http://127.0.0.1:11334;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $http_host;
    }

注意这里给静态文件设置了过期时间,不然每次访问都要下载那些文件,非常慢。我是挂载在子路径下的,需要通过 rewrite 配置把子路径给删掉再传给 rspamd,不然会出问题。

邮件客户端自动配置

上边提到了 SRV 记录并不管用。实际上管用是在 https://autoconfig.example.org/mail/config-v1.1.xml 的配置文件。具体可以看 Lan Tian 的《编写配置文件,让 Thunderbird 自动配置域名邮箱》这篇文章。

Web 邮件客户端

使用的是 Roundcube,是一个 PHP 软件。可以跟着 ArchWiki 的教程配置。注意最好别跟着配置 open_basedir,因为会影响同一 php-fpm 实例上的其它服务。另外记得配过期时间,不然每次都要下载静态资源,很慢的。

因为上边部署了 rspamd 反垃圾服务,所以也可以给 Roundcube 启用一下 markasjunk 插件,并在 /usr/share/webapps/roundcubemail/plugins/markasjunk/config.inc.php 配置一下对应的命令:

$config['markasjunk_spam_cmd'] = 'rspamc learn_spam -u %u -P PASSWORD %f';
$config['markasjunk_ham_cmd'] = 'rspamc learn_ham -u %u -P PASSWORD %f';

不过我配置这个之后,命令会按预期被调用,但是 rspamd 的统计数据里不知为何总显示「0 Learned」。把垃圾邮件通过命令行手动喂给它又会提示已经学过该邮件了。

Category: Linux | Tags: linux mail
12
1
2012
6

继续修改邮件主题

上回说到,中文邮件列表主题标签中的序号让我这位 mutt 用户很是眼烦,于是拿 Python 写了个脚本处理掉了序号。然而,主题中让人眼烦的岂止是标题?看看下面这些:

回复: Re: [shlug] 求助:c程序的效率比java还慢
[CPyUG] Re: [CPyUG:183226] [OT] 自动 tag 加上序号了?

既然已经知道如何处理了,加上有风间星魂的基于正则的极简语法解析器,不妨再处理下。达到的效果如下:

  • 去掉所有的回复字样,在最开头加上「Re: 」
  • 去掉所有标签内的数字
  • 去掉重复的标签

代码在这里。修改后的解析器在这里

Category: python | Tags: mail mutt python
11
24
2012
0

使用 procmail 修改邮件主题

Google Groups 上的邮件列表可以根据管理员的设置自动添加在邮件主题前添加指定的字符串。对于 mutt,固定的字符串没什么,但当这个添加的字符串不断地变化呢?比如这个字符串设置成[vim-cn:%d]%d会被邮件的序号所取代,于是每封邮件都有了不同主题。(对于回复邮件,按 RFC 5322 3.6.5 节的意思,应当将开头的一个Re:不予考虑。)

这样的邮件会话,mutt 一看,哎呀,会话中出现了新的主题,得显示一下啦。于是,本来通常情况下一个会话只会显示一次的邮件主题,在添加了邮件序号后变成了N个。对比下图中黄线上方和下方的区别。

mutt subject display

本来呢,vim-cn 列表是下边那个样子的。最近觉得 vim-cn 的邮件多了起来,看起来眼烦,正好有管理权限,就去把%d删掉了。可谁知我才收到几封不带序号的 vim-cn 邮件呢,python-cn 却开始加序号了,不知道管理员是不是想看看第20万封邮件是谁发的。唉,既然改变不了那个列表的设置,那么就改变本地的邮件处理好了。

在开始使用 mutt 等工具的时候,我一直是把 procmail 当成邮件分发和过滤工具的。如今需要它来修改邮件了,语法还不会呢。另外它的示例中大多是 formail 工具,但我实在不想再学一种语法晦涩的工具了,于是自己搞。本来觉得挺简单的,一句 sed 就能搞定的东西,等真正查看邮件源码时才发现,远没有想像的那么简单!

Subject: =?GB2312?B?W0NQeVVHOjE4MzI0OV0gcHl0aG9uIL+qt6LN+NKz087Pt7rNyta7+rbL?=
        =?GB2312?B?zfjC59POz7e+rdHpx/PW+g==?=

第一,它编码过了;第二,它分成了多行。哦还有第三,邮件正文即使出现也不要处理,不然我这文章发过去不是变了样么?

后两点还好,awk 可以搞定,可是这编码不是那么容易呢,于是用上了 Python。既然 Python 3.3 已经发布,所以试了试新的yield from语法。反正我不认为我会需要在只有 Python 3.2 或者更早的系统上使用这个脚本。

#!/usr/bin/env python3
# vim:fileencoding=utf-8

import sys
import re
from email import header

subject_seq = re.compile(r'''((?:..[::]\s?)?  # Re、回复等
                             \[[^:]+)
                             :\d+              # 要删除的序号''', re.X)

def stripSeq(input):
  subject = None
  while True:
    l = next(input)
    if l.startswith('Subject: '):
      # Subject appears
      subject = l
      continue
    elif subject and l[0] in ' \t':
      # Subject continues
      subject += l
    elif subject:
      # Subject ends
      s = subject[9:]
      h = header.decode_header(s)
      assert len(h) == 1, 'unexpected subject line: ' + s
      s, enc = h[0]
      if isinstance(s, bytes):
        s = s.decode(enc)
      m = subject_seq.match(s)
      if not m:
        yield subject
      else:
        s = m.group(1) + s[m.end():]
        yield 'Subject: ' + header.Header(s, 'utf-8').encode() + '\n'
      subject = None
      yield l
    elif l.strip() == '':
      # mail body
      yield from input
    else:
      yield l

if __name__ == '__main__':
  sys.stdout.writelines(stripSeq(iter(sys.stdin)))

Github 上的地址

procmail 的规则如下,参考了 Stackoverflow 的这个回答

:0 fw
| ~/scripts/python/pyexe/procmail.py
Category: python | Tags: mail mutt python procmail
9
5
2010
2

mutt 带附件转发

mutt带附件转发还真不容易。设置mime_forward_rest变量根本无效,死活就是不带上附近;设置mime_forward倒是把整个邮件都打包成message/rfc822格式的附件发出去了,但叫人怎么读呢?bounce倒是可以,但是不能修改邮件了,大约连原收件人也被bounce给对方了吧。

Google之后,在这里发现了个好办法:

<Esc>e      resend-message         用这封信件作为新信件的模板

这样就可以既编辑信件,又不漏掉附件了。

另外,如果只需要转发附件, 那篇文章还介绍了一个办法,就是在查看附件界面按f转发。这么intuitive的办法我当初怎么没想到呢。。。

Category: Linux | Tags: mutt mail

Mastodon | Theme: Aeros 2.0 by TheBuckmaker.com