はじめに
調査が必要になったので、送信したメールを中継して加工したうえで Office365 へ転送する方法を試してみました。
WSL → telnet → メール送信 → postfix → Python で加工 → sendmail → Office365 のような感じです。
実現方法の確認程度なので、Windows 10 の WSL (Ubuntu 18.04 LTS) を環境として利用しています。
メールの送信も WSL(localhost)内からとして、postfix の設定も動作確認を優先したものとしています。
環境
Windows 10 Pro で WSL (Ubuntu 18.04 LTS) が利用できる環境からスタートしました。
WSL(Windows Subsystem for Linux)の導入とUbuntuの初期設定
- Windows 10 Pro
- WSL (Ubuntu 18.04 LTS)
- Postfix 3.3.0
- Python 3.6.9 + pip
参考にした情報
http://www.postfix.org/FILTER_README.html
https://qiita.com/kanedaq/items/aab362e20bdafea83fff
WSL (Ubuntu 18.04 LTS) への Postfix の導入と中継設定
- postfix をインストールする
$ sudo apt install postfix
- postfix の設定ファイルをコピーして編集する
$ sudo cp /etc/postfix/main.cf.proto /etc/postfix/main.cf
$ sudo vi /etc/postfix/main.cf
- コメントを外したり設定を変更した個所のみ抜粋
# メールシステムのホスト名(FQDN)
myhostname = hostname.example.jp
# メールシステムのドメイン名
mydomain = example.jp
# メールを配信した際に自動補完するドメイン名(ドメイン名とする)
myorigin = $mydomain
# メールを受信するネットワークインターフェイス(すべて)
inet_interfaces = all
# 許可するネットワークレンジ
mynetworks = 127.0.0.0/8
# Postfix の sendmail コマンドのフルパス
sendmail_path = /usr/sbin/sendmail
# Postfix の newaliases コマンドのフルパス
newaliases_path = /usr/bin/newaliases
# Postfix の mailq コマンドのフルパス
mailq_path = /usr/bin/mailq
# メール送信とキュー管理のためのグループ
setgid_group = postdrop
# Postfix の HTML ドキュメントの場所
html_directory = no
# Postfix の マニュアルの場所
manpage_directory = /usr/share/man
# Postfix の サンプル設定ファイルの場所
sample_directory = /etc/postfix
# Postfix の README ファイルの場所
readme_directory = /usr/share/doc/postfix
# ここから設定ファイルの下部に追記
# 転送先の上位メールサーバ(今回は Office365)
relayhost = [smtp.office365.com]:587
# SMTP-AUTH を有効
smtp_sasl_auth_enable = yes
# 転送先のサーバのアドレスと認証するユーザ名とパスワードを記述したファイル
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
# 匿名ログインを許可しない
smtp_sasl_security_options = noanonymous
# 転送先のサーバの SASL メカニズムに対するフィルタ
smtp_sasl_mechanism_filter = LOGIN
# 可能ならば TLS 暗号化
smtp_tls_security_level = may
# CA証明書(ca-certificates)
smtp_tls_CApath = /etc/ssl/certs/ca-certificates.crt
- SMTP-AUTH の転送先のサーバのアドレスと認証するユーザ名とパスワードを記述したファイルを作成する
$ sudo vi /etc/postfix/sasl_passwd
- 転送先のサーバのアドレスと認証するユーザ名とパスワードを記述する
[smtp.office365.com]:587 ユーザー名(メールアドレス):パスワード
- ファイルのパーミッションを変更する
$ sudo chmod 600 /etc/postfix/sasl_passwd
- Postfix が参照するデータベースファイルに反映する
$ sudo postmap hash:/etc/postfix/sasl_passwd
- Postfix を再起動する
$ sudo service postfix restart
- ログを確認する
$ tail -f /var/log/mail.log
$ cat /var/log/mail.err
- 参考)ログが出力されない場合、rsyslog のプロセスや設定や状態を確認する
# プロセスの確認
$ ps aux|grep rsyslog|grep -v grep
# 設定の確認
$ sudo /usr/sbin/rsyslogd -n -d
$ cat /etc/rsyslog.d/50-default.conf
# 状態の確認
$ sudo /etc/init.d/rsyslog status
# プロセスの開始
$ sudo /etc/init.d/rsyslog start
-
参考)このようなエラーがログに記録されている場合はメールエイリアスのデータベースを再構築してみる
error: open database /etc/aliases.db: No such file or directory
# Postfixを停止してメールエイリアスのデータベースを再構築して開始
$ sudo service postfix stop
$ sudo newaliases
$ sudo service postfix start
# メールエイリアスのデータベースの存在確認
$ ls /etc/aliases.db
送信したメールを中継して Office365 へ転送する確認
- telnet を利用してメール中継を確認する
$ telnet hostname.example.jp 25
- 確認のためのメールを送信する
Trying 127.0.1.1...
Connected to hostname.example.jp.
Escape character is '^]'.
220 hostname.example.jp ESMTP Postfix (Ubuntu)
(入力) HELO hostname.example.jp
250 hostname.example.jp
(入力) MAIL From: 送信元メールアドレス
250 2.1.0 Ok
(入力) RCPT To: 送信先メールアドレス
250 2.1.5 Ok
(入力) DATA
354 End data with <CR><LF>.<CR><LF>
(入力) This is test mail.
(入力) .
250 2.0.0 Ok: queued as EAD291C000000084498
(入力) quit
221 2.0.0 Bye
Connection closed by foreign host.
-
Office365 のアカウントを設定している MUA( Outlook )で、中継したメールが受信できることを確認する
-
メールが受信できない場合はログを確認してみる
$ tail -f /var/log/mail.log
$ cat /var/log/mail.err
Postfix の content_filter を利用して Python プログラムでフィルタ
- Python3 と pip をインストールする
$ sudo apt install python3
$ sudo apt install python3-pip
- Python のバージョンを確認する
$ python3 -V
$ pip3 -V
- プログラムを配置するディレクトリとファイルを作成する
$ cd ~
$ mkdir postfix
$ cd postfix
$ touch transfer_mail.py
$ chmod 755 transfer_mail.py
- プログラムを書く
# !/usr/bin/python3
import sys
import os
import email
import email.parser
from os.path import join, dirname
from subprocess import Popen, PIPE
# 標準入力から取得
mime_str = sys.stdin.read()
# mime_str = open(sys.argv[4]).read()
# Eメールとして解析
message = email.parser.Parser().parsestr(mime_str)
# メールの内容を吐き出すファイル
filepath = join(dirname(__file__), 'result.txt')
# メールの内容をファイルに吐き出す
with open(filepath, mode='w') as f:
# パラメータ
for arg in sys.argv:
f.write(f"{arg}\n")
# メールヘッダ
for key in message.keys():
value = message.get(key)
f.write(f"{key} : {value}\n")
# メール本文
payload = message.get_payload()
f.write(payload)
# 送信元、送信先、件名を設定
message["From"] = sys.argv[1]
message["To"] = sys.argv[2]
message["Subject"] = "Test mail !!!"
# メールを転送
command = ["/usr/sbin/sendmail", "-t", "-oi"]
stdout = ''
stderr = ''
retval = 0
process = Popen(command, stdin=PIPE)
(stdout, stderr) = process.communicate(message.as_string().encode())
retval = process.wait()
if retval == 0:
sys.exit(0)
else:
sys.exit(1)
- Postfix の master.cf を編集する
$ sudo vi /etc/postfix/master.cf
- コメントを外したり設定を変更した個所のみ抜粋
# content_filter を指定する
smtp inet n - n - - smtpd -o content_filter=filter:dummy
# content_filter を定義する(実行ユーザー、実行するプログラム、送信者、受信者、サイズ)
filter unix - n n - 10 pipe
flags=Rq user=ユーザー argv=/home/ユーザー/postfix/transfer_mail.py ${sender} ${recipient} ${size}
- Postfix を再起動する
$ sudo service postfix restart
- ログを確認する
$ tail -f /var/log/mail.log
$ cat /var/log/mail.err
送信したメールを中継して Python で加工して Office365 へ転送する確認
- telnet を利用してメール中継を確認する
$ telnet hostname.example.jp 25
- 確認のためのメールを送信する
Trying 127.0.1.1...
Connected to hostname.example.jp.
Escape character is '^]'.
220 hostname.example.jp ESMTP Postfix (Ubuntu)
(入力) HELO hostname.example.jp
250 hostname.example.jp
(入力) MAIL From: 送信元メールアドレス
250 2.1.0 Ok
(入力) RCPT To: 送信先メールアドレス
250 2.1.5 Ok
(入力) DATA
354 End data with <CR><LF>.<CR><LF>
(入力) This is test mail.
(入力) .
250 2.0.0 Ok: queued as EAD291C000000084498
(入力) quit
221 2.0.0 Bye
Connection closed by foreign host.
-
Office365 のアカウントを設定している MUA( Outlook )で、中継したメールが受信できたことを確認する
-
テキストファイルが出力されたことを確認する
$ cat ~/postfix/result.txt
- テキストファイルの内容
/home/ユーザー/postfix/transfer_mail.py ← 実行したプログラム
送信元メールアドレス ← フィルタのパラメータ1
送信先メールアドレス ← フィルタのパラメータ2
サイズ ← フィルタのパラメータ3
Return-Path : <中継メールアドレス>
Received : from hostname.example.jp (localhost [127.0.0.1])
by hostname.example.jp (Postfix) with SMTP id 923AE9E00000003FBF1
for <送信先メールアドレス>; Fri, 9 Oct 2020 23:55:00 +0900 (JST)
Message-Id : <20201009113146.923AE9E00000003FBF1@hostname.example.jp>
Date : Fri, 10 Oct 2020 23:55:00 +0900 (JST)
From : 送信元メールアドレス
This is test mail.(本文)
- ログを確認する
$ tail -f /var/log/mail.log
Oct 10 23:55:00 hostname postfix/qmgr[10858]: 923AE9E00000003FBF1: from=<送信元メールアドレス>, size=362, nrcpt=1 (queue active)
Oct 10 23:55:00 hostname postfix/pipe[10951]: 923AE9E00000003FBF1: to=<送信先メールアドレス>, relay=filter, delay=591, delays=591/0.01/0/0.08, dsn=2.0.0, status=sent (delivered via filter service)
Oct 10 23:55:00 hostname postfix/qmgr[10858]: 923AE9E00000003FBF1: removed
Oct 10 23:55:00 hostname postfix/pickup[10857]: 2047A9F00000003FBF1: uid=1000 from=<ユーザー>
Oct 10 23:55:00 hostname postfix/cleanup[10955]: 2047A9F00000003FBF1: message-id=<20201009113146.923AE9E00000003FBF1@hostname.example.jp>
Oct 10 23:55:00 hostname postfix/qmgr[10858]: 2047A9F00000003FBF1: from=<ユーザー@hostname.example.jp>, size=567, nrcpt=1 (queue active)
Oct 10 23:55:00 hostname postfix/smtp[10957]: warning: vstream_tweak_tcp: getsockopt TCP_MAXSEG: Protocol not available
Oct 10 23:55:00 hostname postfix/smtp[10957]: 2047A9F00000003FBF1: to=<送信先メールアドレス>, relay=smtp.office365.com[XXX.XXX.XXX.XXX]:587, delay=1.6, delays=0.03/0.02/1.1/0.4, dsn=2.0.0, status=sent (250 2.0.0 OK <20201009113146.923AE9E00000003FBF1@hostname.example.jp> [Hostname=XXXXXXXXXXXXX.xxxxxxxx.xxxx.outlook.com])
Oct 10 23:55:00 hostname postfix/qmgr[10858]: 2047A9F00000003FBF1: removed
おわりに
ログの vstream_tweak_tcp の警告が気になりますが、送信したメールを中継して加工したうえで Office365 へ転送することができました。
他サービスとの連携や開発時の調査などに利用できそうです。