6
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

メールを送信する際に存在するメールアドレスかどうか判定する

Last updated at Posted at 2017-11-08

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

コード

app/controllers/concerns/mail_check.rb
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通までしか使えないので。。。

6
11
3

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
6
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?