LoginSignup
1
4

More than 3 years have passed since last update.

WSL に postfix を導入して Office365 宛のメールを中継して Python で加工する

Posted at

はじめに

調査が必要になったので、送信したメールを中継して加工したうえで 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 へ転送することができました。
他サービスとの連携や開発時の調査などに利用できそうです。

1
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
4