deviseでユーザーをメールアドレスで登録する際に、登録と同時にメールを送信していたのですが、そのメールアドレスが本当に生きているか確認する必要があったので実装してみました。
参考にしたサイト https://github.com/kurochan/mail-address-checker/blob/master/mail-address-checker.rb
備忘録程度に書いたので、何か質問があればコメント欄に。。。
実行環境
- OSX 10.11.6
- Rails 5.0.4
- Ruby 2.3.1
- net-telnet 0.1.1
コード
require 'resolv'
module MailCheck
extend ActiveSupport::Concern
MY_DOMAIN = 'gmail.com'.freeze
TIMEOUT = 20
def mail_check(addr)
domain = addr.split('@')[1]
return { exist: false, valid: true, message: 'SMTP Server Not Found' } unless get_exchange(domain)
begin
addrs_exist?(get_exchange(domain), addr)
rescue
return { exist: false, valid: true, message: "Unknown Error.(Maybe #{addr} Does Not Exists.)" }
end
end
private
def get_exchange(domain)
begin
mx = Resolv::DNS.new.getresource(domain, Resolv::DNS::Resource::IN::MX)
rescue
return nil
end
mx.exchange.to_s
end
def addrs_exist?(domain, addr)
status = ''
pop = Net::Telnet.new(Host: domain, Port: 25, Timeout: TIMEOUT, Prompt: /^(2\d{2}|5\d{2})/)
pop.cmd("helo #{MY_DOMAIN}")
pop.cmd("mail from:<#{mail_address}>") # mail_addressには送信元のメールアドレスを入れる
pop.cmd("rcpt to:<#{addr}>") { |c| status << c }
pop.cmd('String' => 'quit')
/^250/ === status
end
end
インスタンスメソッドはmail_check
です。
コントローラー側でMailCheck
モジュールをinclude
してやり、mail_check
メソッドの引数にチェックしたいメールアドレスを入れるだけ。
あとはstatus
にステータスを含む文字列が入っているので、それを元に判定すればいいだけです。
ドメイン等の設定はプロジェクトの環境に合わせてください。
追記
addrs_exist?メソッドが真偽値を返さないので、修正しています。
なので、addrs_exist?メソッドで判定できます。
懸念点
なぜか存在しないメールアドレスでも、存在するステータスを返すことがある。
マジで謎です。
ターミナル上のtelnetで上記と同じコマンドを打つと、存在しないメールアドレスのときは5xx系のステータスが吐かれます。
でもgemだとうまくいかない。じゃあ何で書いたんだよって言われてしまえばそこまでなんですが。。。
せっかく作ったので;;;;
終わりに
存在しないドメインを渡した場合(@asdfa.jp.comなど)は必ずエラーのステータスが吐かれるので使えるかもです。
後日SMTPライブラリで同じような実装を行ってみます。
アデュ。
追記
https://tools.verifyemailaddress.io
↑こんなAPIもあったので使いたかったんですけどね。。。
なにせ100通までしか使えないので。。。