SMTP勉強

とりあえず,RubySMTPSSLを使う練習.四苦八苦で笑えるかもよ.


まずは,実行してみたソースコード

# test_smtp.rb
require 'smtp.rb' # cvsの最新のコードを落としてきたもの
require 'tmail' # 外部のファイルから読み込みたいだけ

# メールのテキスト
mail = TMail::Mail.load('mail5.txt')

# mail.date = Time.now

# GMail Account & password
account = 'account'
pass = 'password'

address = 'smtp.gmail.com'
port = '465' # TLSなら587なのかな?

helo = 'localhost.localdomain'

smtp = Net::SMTP.new(address, port)

smtp.enable_ssl(OpenSSL::SSL::SSLContext.new)
# verify modeをVERIFY_PEERにしちゃダメっぽいので,
# enable_sslの引数のssl_contextをこんな感じに.
# smtp.rbのdefault_ssl_context(@ssl_context)は,verify_modeが
# VERIFY_PEERになっていて,それだとエラーが起きた.

smtp.start(helo, account, pass, :login) # hoge

smtp.send_message(mail.to_s, mail.from.to_s, mail.to.to_s) # fuga

smtp.finish # piyo

なんせSSLTLSの違いがわからんので,とりあえずSSLでやって,下手鉄砲を撃ちまくってみた結果です.ちなみに,以降のエラー文の,test_smtp.rbにおいてエラーが発生した箇所は,実際の行数と異なりますので,ラベルを付けてみたり.

とりあえずSSLでやってみたときのエラーメッセージは?

$ ruby test_smtp.rb
./smtp.rb:703:in `authenticate': undefined method `funcall' for 
#<Net::SMTP smtp.gmail.com:465 started=false> (NoMethodError)
        from ./smtp.rb:546:in `do_start'
        from ./smtp.rb:507:in `start'
        from test_smtp.rb:23 # hoge

funcallが無いとか言われても,すげー困る.

smtp.rbのfuncallって何なの?

funcallは意味わかんないので,試しにコメントアウトしてみる

    def authenticate(user, secret, authtype)
      check_auth_method authtype
      check_auth_args user, secret
      # funcall "auth_#{authtype || 'cram_md5'}", user, secret
    end

こんな感じにしてみて,実行

$ ruby test_smtp.rb
./smtp.rb:898:in `check_response': 530 5.5.1 Authentication Required 
*********** (Net::SMTPUnknownError) # なんか乱数のような文字列さ
        from ./smtp.rb:863:in `getok'
        from ./smtp.rb:793:in `mailfrom'
        from ./smtp.rb:633:in `send_message'
        from test_smtp.rb:24 # fuga

check_responseで,上のメソッドauthenticateに関係しそうなところでエラーが起こった.ソースコードを読んでいて考えたのは,たぶんだけど,funcallってのはauth_#{authtype || 'cram_md5'}って名前のメソッドにuserとsecretを渡して呼び出す,みたいな動きをすると思うんだ.だから,sendで良いと思うの.ボクは.結局,こうすると解決した.

    def authenticate(user, secret, authtype)
      check_auth_method authtype
      check_auth_args user, secret
      self.send "auth_#{authtype || 'cram_md5'}", user, secret
    end

funcall→self.sendの結果は?

この状態でtest_smtp.rbを実行してみると,エラーメッセージこそ出るものの,ちゃんと最終行まで行ってる.てことは,Authenticateできたってことだよね.今回は自分のgmailのアドレスから自分のgmailのアドレスに送ったんだけれども,実際にGMailを開いてみると送信済みメッセージと受信メッセージに追加されていた.さて,お次のエラーはというと,

$ ruby test_smtp.rb
/opt/local/lib/ruby/1.8/net/protocol.rb:133:in `sysread': 
end of file reached (EOFError)
        (略)
        from ./smtp.rb:587:in `do_finish'
        from ./smtp.rb:516:in `finish'
        from test_smtp.rb:26 # piyo

ということで,Net::SMTP#finishを考えないといけないようだ.

finish,それはコネクションのクローズ

これは,先例があるので簡単に解決できた.ありがたや.


id:zorio:20060416:1145206278

どうも、GMailはQUITを送ると応答を返さずにコネクションを切断するようだ。
どうするのが正しいのか分からんので、とりあえず保留。

これの解法は,id:zorio:20060417:1145281299に載っていたので,それをそのまま適応する.

    def quit
      begin
        getok('QUIT')
      rescue EOFError
      end
    end

とすると,一番上に載せたスクリプトは,エラーを吐く事無く実行が終了し,ホッと胸を撫で下ろすボクがそこに居るのでした.


id:zorioさんみたいな人が居ないと,ボクはいつまでたっても迷える子羊だったのだろうか(たぶん最新バージョンのsmtp.rbの存在は知ることが無かったと思う).