スポンサーリンク

2016年2月15日

Erlangのsslモジュールを使いsmtp.gmail.comに接続しメールを送る

Goal

  • Erlangのsslモジュールを使い、smtp.gmail.com:465へ接続する
  • Erlangのsslモジュールを使い、Gmailのアカウントへメールを送信する
  • バレンタイン企画(にしたかった…)

Dev-Environment

OS: Windows8.1
Erlang: Eshell V7.2.1, OTP-Version 18.1

Text

本来であれば、ElixirのMailmanライブラリを利用してGmailへ送りたかったのですが、
私の技術力不足により、送りまでに至りませんでした。(STARTTLSができないため???)
記事にしている皆様方はどうやって送っているのでしょうか…直接お聞きしたいくらいです(英語できませんがw)
それはさておき、できないままと言うのも非常に腹立たしいので、
Erlangのsslモジュールを利用してsmtp.gmail.comへ接続し、
そこから認証を経てメールを送信する方法で自分のGmailアカウントへメールを送ってみます。
まずは、sslモジュールを使って接続する方法について

Example:

1> application:start(asn1).
ok
2> application:start(crypto).
ok
3> application:start(public_key).
ok
4> application:start(ssl).
ok
5> {ok, Socket} = ssl:connect("smtp.gmail.com", 465, [{active, false}], 1000).
{ok,{sslsocket,{gen_tcp,#Port<0.898>,tls_connection,
                        undefined},
               <0.54.0>}}
6> ssl:close(Socket)
アプリケーションで開始させるモジュールがいっぱいありますね…
とりあえず、これでコネクションを接続して閉じるまでができました。
ちまちまやっていこうかと思いましたが、
さっさと結論出せと思いますので一気にやっていきます。
といっても、情けない話ですが参考にしたサイトそのままです(汗)
まずはソースコードから…

File: ssl_send_mail.erl

-module(ssl_send_mail).
-export([connect/0]).

connect() ->
  {ok, Socket} = ssl:connect("smtp.gmail.com", 465, [{active, false}], 1000),
  recv(Socket),
  send(Socket, "HELO localhost"),
  send(Socket, "AUTH LOGIN"),
  send(Socket, binary_to_list(base64:encode("your_gmail_account@gmail.com"))),
  send(Socket, binary_to_list(base64:encode("application_specific_password"))),
  send(Socket, "MAIL FROM: <from@gmail.com>"),
  send(Socket, "RCPT TO:<to@gmail.com>"),
  send(Socket, "DATA"),
  send_no_receive(Socket, "From: <from@gmail.com>"),
  send_no_receive(Socket, "To: <to@gmail.com>"),
  send_no_receive(Socket, "Date: Sun, 14 Feb 2016 23:52:43 +0000"),
  send_no_receive(Socket, "Subject: Noreply"),
  send_no_receive(Socket, ""),
  send_no_receive(Socket, "This is a test mail message"),
  send_no_receive(Socket, ""),
  send(Socket, "."),
  send(Socket, "QUIT"),
  ssl:close(Socket).

send_no_receive(Socket, Data) ->
  ssl:send(Socket, Data ++ "\r\n").

send(Socket, Data) ->
  ssl:send(Socket, Data ++ "\r\n"),
  recv(Socket).

recv(Socket) ->
  case ssl:recv(Socket, 0, 1000) of
    {ok, Result} -> io:format("~p~n", [Result]);
    {error, Reason} -> io:format("ERROR: ~p~n", [Reason])
  end.
実行内容は以下のようになります。

Example:

> erl
Eshell V7.2.1  (abort with ^G)
1> ls().
erlang_ssl_module_connect.txt     ssl_send_mail.erl
ok
2> c(ssl_send_mail).
{ok,ssl_send_mail}
3> application:start(asn1).
ok
4> application:start(crypto).
ok
5> application:start(public_key).
ok
6> application:start(ssl).
ok
7> ssl_send_mail:connect().
"220 smtp.gmail.com ESMTP tp6sm32218402pab.25 - gsmtp\r\n"
"250 smtp.gmail.com at your service\r\n"
"334 VXNlcm5hbWU6\r\n"
"334 UGFzc3dvcmQ6\r\n"
"235 2.7.0 Accepted\r\n"
"250 2.1.0 OK tp6sm32218402pab.25 - gsmtp\r\n"
"250 2.1.5 OK tp6sm32218402pab.25 - gsmtp\r\n"
"354  Go ahead tp6sm32218402pab.25 - gsmtp\r\n"
"250 2.0.0 OK 1455462370 tp6sm32218402pab.25 - gsmtp\r\n"
"221 2.0.0 closing connection tp6sm32218402pab.25 - gsmtp\r\n"
ok
8>
gmailの方を確認に行きます…よし、送れてますね!
(受信時間がおかしいが、Date:の設定をちゃんとしてなかったためでしょう)
何にせよ、これでErlang(sslモジュール)からメールを送信することができました。

Note:

"application_specific_password"ですが、アプリパスワードを指定する必要があります。
アプリパスワードの取得はGoogleのサポートページを参考にして下さい。
参考: https://support.google.com/accounts/answer/185833?hl=ja

追記(20160215)

上記のコードをElixirコードに変換しました。 -> 次の記事

Bibliography

人気の投稿