メールフォームから
メールを送る近代的な方法
@azumakuniyuki
YAPC::Kansai 2017 Osaka 2017/03/4(土) MOTEXさん
メールフォームから
メールを送る近代的な方法
@azumakuniyuki
YAPC::Kansai 2017 Osaka 2017/03/4(土) MOTEXさん
メール送信
温故知新
自己紹介@azumakuniyuki (東邦之)株式会社Cubicroot (京都市)
3
- インフラエンジニア(ラック実装から構築・保守) - *BSD, Linux, 古くはSolaris, SunOS - ネットワークの設計・サーバの構築と保守 - インフラのコード化支援(Ansible,Serverspec)
- 数年前からプログラマー - 主にPerl, Rubyも - サイトの開発(バックエンド) - メール関連の開発
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
ニャーン4YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
子曰
温故而知新
可以為師矣
論語・爲政第二
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
子曰
温故而知新
可以為師矣
論語・爲政第二
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
7
/usr/sbin/sendmail
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
/usr/sbin/sendmail8
- 信頼と実績・歴史と伝統のSendmailそのもの- -rwxr-sr-x root smmsp sendmail* - setgidされたやつ - おなじみのコマンドは全部/usr/sbin/sendmailが実体 - /usr/bin/newaliases - /usr/bin/mailq
必ずある(V8Sendmail)
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
9
- /etc/alternatives/mta - Postfixと同居しているパターン多い - /usr/sbin/alternatives(8)で切り替えられる - /usr/sbin/sendmail.sendmail - /usr/sbin/sendmail.postfix
必ずある(何かと同居)/usr/sbin/sendmail
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
10
- Sendmailを駆逐したい勢力- Sendmailが捨てられて何かに置き換わっている - /var/qmail/bin/sendmail - /usr/bin/exim - macOS $ strings /usr/sbin/sendmail | grep postfix
必ずある(入れ替わってる?)/usr/sbin/sendmail
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
11
- どれも本家の/usr/sbin/sendmailとある程度の互換性がある - my $sendmail = '/usr/sbin/sendmail -t'; - php.ini/sendmail_path= - ; (default: "sendmail -t -i").- CGI::FormBuilder - qw(/usr/lib/sendmail /usr/sbin/sendmail /usr/bin/send...- LWP::Protocol::mailto - qw(/usr/sbin/sendmail /usr/lib/sendmail /usr/ucblib/s...
存在する前提になってる/usr/sbin/sendmail
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
12
$ hostname | mail -s 'Nyaan' [email protected]
$ ls -laF `which mail`lrwxrwxrwx ... /usr/bin/mail -> mailx*
$ strings /usr/bin/mailx | grep sendmail/usr/sbin/sendmail
存在する前提になってる/usr/sbin/sendmail
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
13
無いといろいろマズい、たぶん/usr/sbin/sendmail
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
14
127.0.0.1:25
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
15
25 = SMTP
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
16
$ netstat -na | grep LISTEN | grep -E ':(25|587)'tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTENtcp6 0 0 ::1:25 :::* LISTEN
# /usr/sbin/lsof -i:25COMMAND PID USER ...sendmail 2401 root ... localhost:smtp (LISTEN)
MTAでなくても動いてる127.0.0.1:25
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
17
# mailq -Ac /var/spool/clientmqueue (1 request)...v22IJrNi0022 ... Fri Mar 3 02:22 root (Deferred: Connection refused by [127.0.0.1]) [email protected]
# crontabの結果がメールで来ないとか、いろいろ困る。
動いてないとキューに溜まる127.0.0.1:25
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
18
動いている前提になっているlocalhost:25
- Mail::Sendmail - 'smtp' => [ qw( localhost ) ],- Email::Sender - ::Transport::SMTP - has host => (..., default => sub { 'localhost' });- Email::Send::SMTP - my $host = delete($args{Host}) || 'localhost';
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
19
To: [email protected]ニャーン
里親になる!なまえメールでんわ
@
送信
/usr/bin/mail*smtp.nyaan.jp:25
Sendmail, Postfix, ...
~/dead.letter Mail Queue
127.0.0.1:25
/usr/sbin/sendmail*
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
20
192.0.2.222:25
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
21
別のSMTPサーバを経由する192.0.2.222:25
- 多くのWebサーバから外へ出るメールのゲートウェイとして - ゲートウェイ? - ウィルスチェックをするとか - 特定のFrom:なメールだけ通過させる - 野良メールはゲートウェイで捨てる - 優先度(Precedence:)別に処理するとか - 登録完了系はすぐに送信 - お知らせ系はキューに貯めて毎時0分に送信
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
22
今は外へメールが送りにくい192.0.2.222:25
- OP25B: Outbound Port 25 Blocking - 一般家庭の回線から外部のSMTPへ接続できない - ISPがブロックしている - 固定IPアドレスの回線なら外向きのSMTP接続も大丈夫- SPF: Sender Policy Framework - DNSのTXTレコードで設定されている - 「**@nyaan.jpは192.0.2.222からしか送信しませんよ」 - ↑TXTに書いていないとこからのメールは「迷惑メール」行き?
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
23
To: [email protected]ニャーン
里親になる!なまえメールでんわ
@
送信
/usr/bin/mail*smtp.nyaan.jp:25
Sendmail, Postfix, ...
~/dead.letter Mail Queue
127.0.0.1:25
/usr/sbin/sendmail*192.0.2.222:25
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
24
smtp.gmail.com:587
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
25
587 = Submission
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
26
SMTP認証を経てメール投函smtp.gmail.com:587
- 587 = Submission - <input type = 'submit' value = '送信'>- 素数- 587番ポートは認証が必須(で設定されているのが殆ど)- OP25Bな環境では(ほぼ)唯一のメール送信方法- ほとんどのメールサーバはSubmissionに対応している - Gmail, Office365, Yahoo!, SendGrid, Amazon SES - 会社のメールサーバとか(Sendmail, Postfix, ...)
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
27
Email::Sendersmtp.gmail.com:587
use Email::Sender;my $SMTP = Email::Sender::Transport::SMTP->new( 'host' => 'smtp.gmail.com', 'port' => 587, 'sasl_username' => '*********@gmail.com', 'sasl_password' => '*************');
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
28
Net::SMTP or Net::SMTPSsmtp.gmail.com:587
use Net::SMTP; # TLSで通信するならNet::SMTPS;use Authen::SASL;my $smtp = Net::SMTP->new('smtp.gmail.com', 'Port'=>587);my $auth = Authen::SASL->new('callback' => { 'user' => '*******@gmail.com', 'pass' => '********'};$smtp->auth($auth);
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
29
Sendmail (/etc/mail)smtp.gmail.com:587
# grep authinfo sendmail.cfKauthinfo hash /etc/mail/authinfo
# vi authinfoAuthinfo:smtp.gmail.com "U:**@gmail.com" "P:**" "M:plain"
# makemap hash authinfo < authinfo# chmod 0600 ./authinfo
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
30
Postfix (/etc/mail/postfix)smtp.gmail.com:587
# grep smtp_sasl main.cfsmtp_sasl_auth_enable = yessmtp_sasl_password_maps = hash:/etc/postfix/authinfo
# vi authinfo[smtp.gmail.com]:587 ***@gmail.com:****
# /usr/sbin/postmap authinfo# chmod 0600 ./authinfo*
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
31
To: [email protected]ニャーン
里親になる!なまえメールでんわ
@
送信
/usr/bin/mail*smtp.nyaan.jp:25
smtp.GMail.com:587Sendmail, Postfix, ...
~/dead.letter Mail Queue
127.0.0.1:25
/usr/sbin/sendmail*192.0.2.222:25
#! /usr/bin/env perl
use Net::SMTP;use Email::MIME;
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
32
「温故」編まとめSMTP or Submission
a. /usr/sbin/sendmailが要る - コマンドラインでも送れるしb. 127.0.0.1(localhost)の25番ポートでMTAが動いている - Net::SMTPとか使っても送れるc. 25番ポートにSMTP接続できる別サーバが要る - WebサーバでMTAが動いていない時のためd. 587番ポートで認証できるアカウントとサーバが要る - OP25Bでブロックされている時
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
子曰
温故而知新
可以為師矣
論語・爲政第二
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
34
443 = HTTPS
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
35
メール配信サービスのAPIHTTP API
- 有名且つ大きいところ - Amazon SES https://aws.amazon.com/jp/ses - SendGrid https://sendgrid.kke.co.jp/- 信頼と実績・歴史と伝統のSMTPインターフェイスもある - Submission(認証して)で送る - SMTPアレルギーが無いなら楽かも、たぶん。- HTTP(HTTPS)で送信する方が速い - 大量に送るならHTTP-APIを使う方が良い
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
36
AmazonSESのモジュールHTTP API
- Amazon::SES - 依存: [JSON::XS, Moo, LWP::UserAgent, ...]
- Net::AWS::SES - 依存: [HTTP::Headers, LWP::UserAgent, MIME::*]
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
37
SendGridのモジュールHTTP API
- Mojo::SendGrid (Mojolicious) - 2016年3月に登場した(新しい!)
- Mail::SendGrid - 2011年からある - 依存: [HTTP::Tiny, IO::Socket::SSL, JSON, Moo, ...]
- WebService::SendGrid - 依存: [JSON::XS, Moose, DateTime::Formt::HTTP, ...]
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
38
僕?HTTP API
use Furl;my $http = Furl->new(...);my $mail = { 'to' => '[email protected]', 'from' => '[email protected]', 'subject' => 'Nyaan', 'text' => Encode::encode('UTF-8', 'にゃーん'), ... };$http->post('https://sendgrid.net/api/mail.send.json',, $mail);
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
39
依存が少ないのを選んでるHTTP API
- 依存が沢山あるモジュールは好みでは無い - Perlのコアモジュールなら少しぐらいOK- 開発時間 < コードが動いている時間 - 依存は少ない方がええやんね - 極少人数開発が多いし - 依存先モジュールの変更点を追いかけるのは大変やし...
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
40
To: [email protected]ニャーン
里親になる!なまえメールでんわ
@
送信
/usr/bin/mail*smtp.nyaan.jp:25
smtp.GMail.com:587Sendmail, Postfix, ...
~/dead.letter Mail Queue
127.0.0.1:25
/usr/sbin/sendmail*192.0.2.222:25
email.us-east-1...:443
sendgrid.com:443
#! /usr/bin/env perl
use Furl;use Email::MIME;
#! /usr/bin/env perl
use Net::SMTP;use Email::MIME;
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
41
SMTPor
HTTP
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
42
どっちが良いの?
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
43
SMTPの良いところSMTP or HTTP
- MTAが操作できるなら非常に柔軟なことができる- 手持ちのSMTP(Submission)アカウントで送信OK - Gmail, Yahoo!でなくても自前で建てたサーバ経由でもOK- そもそも昔からある汎用的な技術で枯れている! - 選択肢が多い - Sendmail, Postfix, qmail, Exim4, OpenSMTPD, Exchange, - qpsmtpd- コマンドラインから手軽に送信(mailx, telnet)
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
44
HTTPの良いところSMTP or HTTP
- MTA(SendmailやPostfixとか)が動いてなくてもOK- そもそもSMTPに関わらなくても良い- Webサイトに組み込みやすい- メールキューの監視・管理をしなくても良い- 外に出やすい(80, 443だけ外出OKとかOP25Bは無関係とか)- テンプレート機能とかメール送信以外が充実
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
45
SMTPのイマイチなところSMTP or HTTP
- MTA(Sendmail, Postfix, ...)が必要になることが多い - Sendmailは難解と言われる - PostfixもSMTPの知識が無いと難しい- キューの管理(たくさん滞留すると大変) - 国内の携帯電話宛とか特に- DNSのことも気にせなアカン- 外出しにくい(OP25BとかSPFとか)- ロストテクノロジー
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
46
HTTPのイマイチなところSMTP or HTTP
- 証明書とか面倒くさい - ちょっとテストしたいだけやのに- キューの制御ができない - 一旦エンドポイントに渡した後は何もできない- Suppressionリストが共有(Amazon SES) - 同じリージョン内でバウンスしたアドレスには送れない - 国内の携帯電話宛では厄介- バウンス情報が少なすぎる(SendGrid)
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
47
適材適所二者択一では無い
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
48
To: [email protected]ニャーン
里親になる!なまえメールでんわ
@
送信
/usr/bin/mail*smtp.nyaan.jp:25
smtp.GMail.com:587Sendmail, Postfix, ...
~/dead.letter Mail Queue
127.0.0.1:25
/usr/sbin/sendmail*192.0.2.222:25
email.us-east-1...:443
sendgrid.com:443
#! /usr/bin/env perl
use Furl;use Email::MIME;
#! /usr/bin/env perl
use Net::SMTP;use Email::MIME;
127.0.0.1:2794
メールのヘッダと本文をJSONで書いてHTTP POST
Haineko
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
49
メールを送った後
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
50
バウンス処理しましょEmail Bounces
- メールアドレスは水物・ナマモノ- Perlなら良いモジュールがある!
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
51
メールを送った後
Sisimai
http://libsisimai.org/
YAPC::Kansai 2017 Osaka | 2017/03/04(土) MOTEXさん
メールフォームからメールを送る近代的な方法 @azumakuniyuki
終