QNAPにメールサーバーをインストールする

QNAPにメールサーバーがないので、Container Stationを使って入れることにする。

# やりたいこと
個人のQNAPにメールサーバーを入れてやりたいことって、だいたいこの3つなんじゃないかなと思う。

* dovecot(+sieve) : IMAPサーバー
* postfix : ローカルのSMTPサーバー。もらったメールはLMTPでdovecotに渡す。
* getmail : 他のアカウントのメールをとってきて集約する

spamassassinもあっていいけど後回し。

# なぜ世の中のメールサービスを使わないでわざわざ自分のサーバーに立てるのか
そこにサーバーがあるから。

# dockerイメージを作ってみる
既に世の中にあるような気もするけど、探すのも面倒なので自分でDockerfileを作る。

## 最初は
最初はお約束のいろいろ。メールの中身などは後でQNAPの共有フォルダーにマウントする。マウント先は/srv/mailとする。

```:Dockerfile
FROM arm32v7/ubuntu:bionic

LABEL version="0.1"
LABEL description="intranet mail server"

EXPOSE 993

VOLUME /srv/mail
```

## パッケージ
以下のパッケージを入れる。

* dovecot-imapd
* dovecot-sieve
* dovecot-lmtpd
* postfix
* getmail
* rsyslog
* cron
* incron
* vim

vim は本当はいらないんだけど、端末から入っていろいろやりたいときにないと不便なので入れておく。

```:Dockerfile
#
# package installation
#
RUN DEBIAN_FRONTEND=noninteractive apt-get update
RUN DEBIAN_FRONTEND=noninteractive apt-get -y upgrade
RUN DEBIAN_FRONTEND=noninteractive apt-get -q -y --no-install-recommends install dovecot-imapd dovecot-sieve dovecot-lmtpd postfix cron incron getmail rsyslog
# for debugging
RUN DEBIAN_FRONTEND=noninteractive apt-get -q -y --no-install-recommends install vim

# Clean
RUN apt-get clean
RUN rm -rf /var/lib/apt/lists/*
```

# システム設定
vmailという名前のグループとユーザーを作る。このgidとuidはQTSと同じものでなくてはならない。
QTSの方は最初のグループが101、最初のユーザーが500になるので、それに合わせておく。

あと、syslogが吐かれるようにrsyslog.confを設定する。

```:Dockerfile
#
# System
#
RUN groupadd -g 101 -o vmail
RUN useradd -u 500 -d /srv/mail -g 101 -M -r -s /bin/false vmail

ADD rsyslog.conf /etc/rsyslog.conf
```

ちなみにsyslogはQTSの方に転送するように設定する。(これで合ってるのかな)

```:rsyslog.conf
module(load="imuxsock")
$RepeatedMsgReduction on
$PrivDropToUser syslog
$PrivDropToGroup syslog
$WorkDirectory /var/spool/rsyslog
*.* @@server (サーバーの名前)
```

## dovecot
dovecotはvirtual userでユーザーは作らずにメールボックスだけ用意する。
証明書(server.pem, server,key)とパスワードファイル(passwd)を別途転送する。

```:Dockerfile
ADD server.pem /etc/dovecot/server.pem
ADD server.key /etc/dovecot/private/server.key
ADD dovecot.conf /etc/dovecot/dovecot.conf
RUN mkdir -p /etc/dovecot/private
RUN chown dovecot /etc/dovecot/private
RUN chmod 700 /etc/dovecot/private
ADD passwd /etc/dovecot/private/passwd
RUN chown dovecot /etc/dovecot/private/passwd
RUN chmod 600 /etc/dovecot/private/passwd
RUN mkdir -p /var/mail
RUN chown vmail:vmail /var/mail
```

dovecot.conf は以下の通り。機能ごとに設定ファイルを分けるのが普通なんだけど、簡単な設定しかしない場合は1つにまとめてしまった方が簡単だよね。

```:dovecot.conf
protocols = imap lmtp

protocol lda {
  mail_plugins = sieve
}

protocol lmtp {
  mail_plugins = sieve
}

#
# Auth
#
auth_mechanisms = plain
passdb {
  driver = passwd-file
  args = username_format=%n /etc/dovecot/private/passwd
}
userdb {
  driver = static
  args = uid=vmail gid=vmail home=/srv/mail/%n
}

#
# Mail Location
#
mail_home = /srv/mail/%n
mail_location = maildir:~/mail:INBOX=~/mail/.INBOX
namespace inbox {
  inbox = yes
}
namespace inbox {
  mailbox Drafts {
    special_use = \Drafts
  }
  mailbox Junk {
    special_use = \Junk
  }
  mailbox Trash {
    special_use = \Trash
  }

  mailbox Sent {
    special_use = \Sent
  }
  mailbox "Sent Messages" {
    special_use = \Sent
  }
}

#
# SSL
#
ssl = required
ssl_cert =</etc/dovecot/server.pem
ssl_key =</etc/dovecot/private/server.key

#
# Sieve
#
plugin {
  sieve = file:~/sieve;active=~/sieve/active.sieve
}

#
# lmtp
#
service lmtp {
  unix_listener /var/spool/postfix/private/dovecot-lmtp {
    user = postfix
    group = postfix
    mode = 0666
  }
}

#
# Log
#
#auth_debug = yes
#auth_verbose = yes
#mail_debug = yes
```

なお、最後の3行をコメントアウトするとログが出力されるようになるので、デバッグ中はつける。

ちなみにpasswdファイルは{plain}をつけてパスワードそのものを書いてもいいんだけど、こんな感じでエンコード後のものを入れる(もちろん本物じゃないよ)。エンコードは```doveadm pw```でできるよ。

```:passwd
user1:jklsdafASFJla342q8fasdfajl$$AJdasix
```

## postfix
ローカルのメールを受け取るために、SMTPサーバーを用意する(もちろん外には開放しない)。

```:Dockerfile
ADD postfix.cf /etc/postfix/main.cf
ADD postfix_vmailbox /etc/postfix/vmailbox
ADD postfix_valias /etc/postfix/virtual
RUN chmod 600 /etc/postfix/vmailbox
RUN chmod 600 /etc/postfix/virtual
```

postfixでは、リレーしないように、バーチャルユーザーに対してdovecotにlmtp経由で放り投げるように設定。

```:postfix.cf
mydomain = MYSERVERNAME.myqnapcloud.com
myorigin = $mydomain
myhostname = MYSERVERNAME
mydestination = $myhostname, localhost
masquerade_domains = $mydomain
masquerade_classes = envelope_sender, envelope_recipient, header_sender, header_recipient
local_header_rewrite_clients = permit_mynetworks
relayhost =
relay_transport = error
mynetworks_style = subnet
inet_interfaces = all
inet_protocols = all
default_transport = error
compatibility_level= 2

smtpd_relay_restrictions = permit_mynetworks defer_unauth_destination

virtual_mailbox_domains = MYSERVERNAME.myqnapcloud.com
virtual_alias_maps = texthash:/etc/postfix/virtual
virtual_transport = lmtp:unix:private/dovecot-lmtp
virtual_minimum_uid = 100
virtual_uid_maps = static:vmail
virtual_gid_maps = static:vmail
```

vmailboxは次のように書く。1列目はメールアドレス、2列目はdovecotに渡すユーザー名。

```:postfix_vmailbox
user1@MYSERVERNAME.myqnapcloud.com user1
```

メールアドレスの変換を入れたい場合(いわゆるalias)、virtualに次のように書く。1列目のメールアドレスが2列目に変換される。

```:postfix_valias
root@MYSERVERNAME.myqnapcloud.com user1@MYSERVERNAME.myqnapcloud.com
postmaster@MYSERVERNAME.myqnapcloud.com user1@MYSERVERNAME.myqnapcloud.com
```

## getmail
getmailで外部のメールサーバーのメールをとってくるようにすると、自動的にsieveで振り分けされるので便利。

getmail自体はデーモンモードはないので、cronで動かす。

普通にaptでインストールすると、なぜかpython2がないと言って動かないので、無理やりpython2にリンクを張っている。

```:Dockerfile
RUN ln -s /usr/bin/python2.7 /usr/bin/python2
ADD getmailrc /etc/getmailrc
RUN chmod 0700 /etc/getmailrc
RUN chown vmail:vmail /etc/getmailrc
```

getmailでは、メールサーバーにPOP3で接続し、あるメールを全部とってきてdovecotへ流す。とってきたメールは削除する。自分専用なので、もう引数にユーザー名も書いてしまう。

```:getmailrc
[retriever]
type = SimplePOP3SSLRetriever
server = MAIL_SERVER_ADDRESS
username = USERNAME
password = PASSWORD

[destination]
type = MDA_external
path = /usr/lib/dovecot/deliver
arguments = ("-e","-d","user1","-r","%(recipient)")

[options]
read_all = true
delete = true
verbose = 0
```


## cron
定期的に動かしたい処理はcronに書いておく。getmailと、あと定期的なメールボックス処理を書く。

```:Dockerfile
USER vmail
ADD crontab /tmp/crontab.services
RUN crontab /tmp/crontab.services
USER root
```

doveadm expunge コマンドは、条件に合致したメールを自動で消してくれる。ここでは、Trash, bulk, logの各フォルダのメールで、保存後30日以上経過したものを自動で消すようにしている。

```:crontab
*/5 * * * * /usr/bin/getmail -r /etc/getmailrc -g /srv/mail/.getmail
36 5 * * * /usr/bin/doveadm expunge -u user1 \( mailbox Trash or mailbox bulk or mailbox log \) savedbefore 30d
```

## 最後に全部を動かす設定
dockerだとsystemdみたいなものはないので、各サービスを順番に起動するrun.shを書いて、CMDで実行できるようにしておく。

```:Dockerfile
ADD run.sh /root/run.sh
RUN chmod 0755 /root/run.sh
CMD /root/run.sh
```

.getmailフォルダはコンテナの外のボリュームに作りたいので、Dockerfileではなく実行時にフォルダを作成する。後は各サービスを起動して無限ループだ。

```shell:run.sh
#!/bin/sh

mkdir -p /srv/mail/.getmail
chmod 0700 /srv/mail/.getmail
chown vmail:vmail /srv/mail/.getmail

#
# Run services
#
/usr/sbin/rsyslogd
/usr/sbin/cron
/usr/sbin/dovecot
/usr/sbin/postfix start

while true
do
    sleep 99999999
done
```