12
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Rails6 アプリからGmailのメールサーバからメールを送信する ローカル環境編

Last updated at Posted at 2020-01-19

目的

  • Rails6で作成したアプリからGmailのメールサーバを利用してメールを送信する方法をまとめる。

前提条件

  • Googleのアカウントを持っていること。
  • Googleの二段階認証の設定がなされていること。
  • Googleのアプリケーション用パスワードを取得していること。
  • 正常に動作しているRails6のアプリがあること。
  • テストメールを送信できるアドレス(メールを送信しても迷惑にならないメールアドレス)を知っていること。
    • 二段階認証、アプリケーション用パスワードを取得しているアカウントのメールアドレスでもOK(自分にテストメールを送信して確認する)

作業期待値

  • とりあえず難しい処理は無しにしてRails6アプリケーションからのメールが送信できるようにする。
  • Rails6のアプリケーションから何かのトリガーを用いてGmailのメールサーバからテストメールを送信する。
  • 継承やその他詳しい話はせずとにかくメールを送信できるようにする。
  • メーラーの詳しい話や処理方法は下記の本のメールについての記載を確認することをオススメする。(アフィリエイトリンクでは無いので安心してください。)

作業の前にちょっと聞いてほしいこと

  • 筆者はこのメールの実装に非常に時間がかかった。
  • データベースの内容をメールに添付しようとしたり、宛先を複数指定したりしたためミスが多くあった。
  • 余計なことは考えずとにかくテストメールを送信できることを最優先に作業をした方が良い気がする。

作業概要

  1. メーラーの作成
  2. 送信アドレス設定
  3. メールサーバの設定
  4. 送信トリガーの設定
  5. テスト送信

作業詳細

  1. メーラーの作成

    1. 下記コマンドを実行してメーラーを作成する。(notice greetingはクラス名とメソット名であるため任意のものでも構わない)

      $ cd アプリ名フォルダ
      $ rails g mailer notice greeting
      
    2. 先のコマンドを実行するとメーラーが作成される。メール送信に必要なファイル群が作成されると思っていただきたい。

  2. 送信アドレス設定

    1. 下記に存在する送信先を指定するファイルnotice_mailer.rbをエディタで開く

      • アプリ名フォルダ/app/mailers
        • notice_mailer.rb
    2. ファイルnotice_mailer.rbの下記の部分を下記のように修正してテストメールを送信する先のアドレスを設定する。

      class NoticeMailer < ApplicationMailer
      
        # Subject can be set in your I18n file at config/locales/en.yml
        # with the following lookup:
        #
        #   en.notice_mailer.greeting.subject
        #
        def greeting
          @greeting = "Hi"
      
          mail to: "to@example.org"
        end
      end
      

      ↓修正

      class NoticeMailer < ApplicationMailer
      
        # Subject can be set in your I18n file at config/locales/en.yml
        # with the following lookup:
        #
        #   en.notice_mailer.greeting.subject
        #
        def greeting
          @greeting = "Hi"
      
          mail to: "テストメール送信先アドレス"
        end
      end
      
  3. メールサーバの設定

    1. 下記に存在する送信先を指定するファイルdevelopment.rbをエディタで開く

      • アプリ名フォルダ/config/environments
        • development.rb
    2. ファイルdevelopment.rbを下記のように修正してテストメールを送信するメールサーバを設定する。

      Rails.application.configure do
        # Settings specified here will take precedence over those in config/application.rb.
      
        # In the development environment your application's code is reloaded on
        # every request. This slows down response time but is perfect for development
        # since you don't have to restart the web server when you make code changes.
        config.cache_classes = false
      
        # Do not eager load code on boot.
        config.eager_load = false
      
        # Show full error reports.
        config.consider_all_requests_local = true
      
        # Enable/disable caching. By default caching is disabled.
        # Run rails dev:cache to toggle caching.
        if Rails.root.join('tmp', 'caching-dev.txt').exist?
          config.action_controller.perform_caching = true
          config.action_controller.enable_fragment_cache_logging = true
      
          config.cache_store = :memory_store
          config.public_file_server.headers = {
            'Cache-Control' => "public, max-age=#{2.days.to_i}"
          }
        else
          config.action_controller.perform_caching = false
      
          config.cache_store = :null_store
        end
      
        # Store uploaded files on the local file system (see config/storage.yml for options).
        config.active_storage.service = :local
      
        # Don't care if the mailer can't send.
        config.action_mailer.raise_delivery_errors = false
      
        config.action_mailer.perform_caching = false
      
        # Print deprecation notices to the Rails logger.
        config.active_support.deprecation = :log
      
        # Raise an error on page load if there are pending migrations.
        config.active_record.migration_error = :page_load
      
        # Highlight code that triggered database queries in logs.
        config.active_record.verbose_query_logs = true
      
        # Debug mode disables concatenation and preprocessing of assets.
        # This option may cause significant delays in view rendering with a large
        # number of complex assets.
        config.assets.debug = true
      
        # Suppress logger output for asset requests.
        config.assets.quiet = true
      
        # Raises error for missing translations.
        # config.action_view.raise_on_missing_translations = true
      
        # Use an evented file watcher to asynchronously detect changes in source code,
        # routes, locales, etc. This feature depends on the listen gem.
        config.file_watcher = ActiveSupport::EventedFileUpdateChecker
      end
      

      ↓修正

      Rails.application.configure do
        # Settings specified here will take precedence over those in config/application.rb.
      
        # In the development environment your application's code is reloaded on
        # every request. This slows down response time but is perfect for development
        # since you don't have to restart the web server when you make code changes.
        config.cache_classes = false
      
        # Do not eager load code on boot.
        config.eager_load = false
      
        # Show full error reports.
        config.consider_all_requests_local = true
      
        # Enable/disable caching. By default caching is disabled.
        # Run rails dev:cache to toggle caching.
        if Rails.root.join('tmp', 'caching-dev.txt').exist?
          config.action_controller.perform_caching = true
          config.action_controller.enable_fragment_cache_logging = true
      
          config.cache_store = :memory_store
          config.public_file_server.headers = {
            'Cache-Control' => "public, max-age=#{2.days.to_i}"
          }
        else
          config.action_controller.perform_caching = false
      
          config.cache_store = :null_store
        end
      
        # Store uploaded files on the local file system (see config/storage.yml for options).
        config.active_storage.service = :local
      
        # Don't care if the mailer can't send.
        # config.action_mailer.perform_caching = false
        config.action_mailer.raise_delivery_errors = true
        config.action_mailer.delivery_method = :smtp
        config.action_mailer.smtp_settings = {
          :enable_starttls_auto => true,
          :address => 'smtp.gmail.com',
          :port => '587',
          :domain => 'smtp.gmail.com',
          :authentication => 'plain',
          :user_name => '二段階認証設定、アプリケーションパスワードを取得したアカウントのメールアドレス',
          :password => 'アプリケーションパスワード(表示された時は4文字で区切られていたがスペース入れず連続して記載)'
        }
      
        # Print deprecation notices to the Rails logger.
        config.active_support.deprecation = :log
      
        # Raise an error on page load if there are pending migrations.
        config.active_record.migration_error = :page_load
      
        # Highlight code that triggered database queries in logs.
        config.active_record.verbose_query_logs = true
      
        # Debug mode disables concatenation and preprocessing of assets.
        # This option may cause significant delays in view rendering with a large
        # number of complex assets.
        config.assets.debug = true
      
        # Suppress logger output for asset requests.
        config.assets.quiet = true
      
        # Raises error for missing translations.
        # config.action_view.raise_on_missing_translations = true
      
        # Use an evented file watcher to asynchronously detect changes in source code,
        # routes, locales, etc. This feature depends on the listen gem.
        config.file_watcher = ActiveSupport::EventedFileUpdateChecker
      end
      
  4. 送信トリガーの設定(ここからは各個人のプロダクトにより若干方法が異なるが、単純に送信のきっかけを作っているだけなので難しく考えないでほしい)

    1. 送信のトリガーとなる処理(以降、メールトリガーコードと呼ぶ)を任意のコントローラファイルに記載する。

    2. 任意のコントローラのアクション内に下記メールトリガーコードを記載する。

      • ※メーラーの作成時にクラス名、メソット名を独自の物にした人は若干異なるので注意
      • ※難しく考えず、下記の処理を記載してコントローラ内で実行してあげればメールが送信されると考えると記載箇所の応用が効きやすいかもしれない
      # メーラークラス名.メール送信メソット名.送信メソット名
      NoticeMailer.greeting.deliver_now
      
    3. 前述の記載を任意のアクション内に記載するが、オススメは任意ページを表示するアクションに記載することである。

    4. 筆者はhttp://localhost:3000/posts/index/:idにアクセスした時にテストメールが送られるように設定した。

    5. 筆者のメールトリガーコードの記載例を下記に記載する。

      • post_controller.rbファイルのindexアクション内に下記を記載
      class PostsController < ApplicationController
        def index
          @posts = Post.where(user_id: @current_user.id)
      end
      

      ↓メールトリガーコードを記載

      class PostsController < ApplicationController
        def index
          NoticeMailer.greeting.deliver_now
          @posts = Post.where(user_id: @current_user.id)
        end
      
  5. テスト送信

    1. 下記コマンドを実行してアプリケーションを起動する。

      $ cd アプリ名フォルダ
      $ rails s
      
    2. アプリケーション内でメールトリガーコードを記載したコントローラのアクションが実行されるようにページ遷移する。

    3. 筆者の場合http://localhost:3000/posts/index/:idにアクセスするとメールトリガーコードが実行されるため上記画面を表示した。

  6. メール確認

    1. 下記のようなメールが送信先アドレスに届いていれば実装完了である。
      スクリーンショット 2020-01-18 11.10.53.png

Net::SMTPAuthenticationErrorのエラー

  1. メールトリガーコードを記載したコントローラのアクションを実行したところエラーNet::SMTPAuthenticationErrorが発生した。
  2. これは二段階認証を使用してGmailのをメールサーバを使用した場合にアプリケーションパスワードが一致していない時に出るエラーらしい。
    • 筆者のエラーメッセージ: 534-5.7.9 Application-specific password required. Learn more at
  3. ファイルdevelopment.rbの二段階認証を行なったアカウントのメールアドレス、パスワードが間違えていないかもう一度確認しよう。
  4. 正常に設定されているなら、railsアプリを終了し10分~20分ほど放置してから再トライしてみよう。
  5. サーバとのやりとりに時間がかかっており、ファイルdevelopment.rbでパスワード設定直後だと接続がうまくいかない恐れがある。(筆者談、真意は不明)

エラーは出てないがメールが来ない

  1. ファイルnotice_mailer.rbで指定している送信先のメールアドレスを入力していないかを確認してみよう。

付録

  • 筆者の環境でメール作成の実績がある各ファイルの内容を下記に記載する。

  • パスワードはダミーを入力する。

  • 今回説明に出てきていないメーラー作成コマンドで作成されたそのほかのファイルの記載状況もまとめる。

  • notice_mailer.rb

class NoticeMailer < ApplicationMailer

  # Subject can be set in your I18n file at config/locales/en.yml
  # with the following lookup:
  #
  #   en.notice_mailer.greeting.subject
  #
  def greeting
    @greeting = "Hi"

    mail to: "shun.okawa@gmail.com",
         cc: "miriwo.rails@gmail.com"
  end
end
  • development.rb
Rails.application.configure do
  # Settings specified here will take precedence over those in config/application.rb.

  # In the development environment your application's code is reloaded on
  # every request. This slows down response time but is perfect for development
  # since you don't have to restart the web server when you make code changes.
  config.cache_classes = false

  # Do not eager load code on boot.
  config.eager_load = false

  # Show full error reports.
  config.consider_all_requests_local = true

  # Enable/disable caching. By default caching is disabled.
  # Run rails dev:cache to toggle caching.
  if Rails.root.join('tmp', 'caching-dev.txt').exist?
    config.action_controller.perform_caching = true
    config.action_controller.enable_fragment_cache_logging = true

    config.cache_store = :memory_store
    config.public_file_server.headers = {
      'Cache-Control' => "public, max-age=#{2.days.to_i}"
    }
  else
    config.action_controller.perform_caching = false

    config.cache_store = :null_store
  end

  # Store uploaded files on the local file system (see config/storage.yml for options).
  config.active_storage.service = :local

  # Don't care if the mailer can't send.
  # config.action_mailer.perform_caching = false
  config.action_mailer.raise_delivery_errors = true
  config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = {
    :enable_starttls_auto => true,
    :address => 'smtp.gmail.com',
    :port => '587',
    :domain => 'smtp.gmail.com',
    :authentication => 'plain',
    :user_name => 'miriwo.rails@gmail.com',
    :password => 'smppyvjbfzhweyxx'
  }

  # Print deprecation notices to the Rails logger.
  config.active_support.deprecation = :log

  # Raise an error on page load if there are pending migrations.
  config.active_record.migration_error = :page_load

  # Highlight code that triggered database queries in logs.
  config.active_record.verbose_query_logs = true

  # Debug mode disables concatenation and preprocessing of assets.
  # This option may cause significant delays in view rendering with a large
  # number of complex assets.
  config.assets.debug = true

  # Suppress logger output for asset requests.
  config.assets.quiet = true

  # Raises error for missing translations.
  # config.action_view.raise_on_missing_translations = true

  # Use an evented file watcher to asynchronously detect changes in source code,
  # routes, locales, etc. This feature depends on the listen gem.
  config.file_watcher = ActiveSupport::EventedFileUpdateChecker
end
  • posts_controller.rb
class PostsController < ApplicationController
  def index
    NoticeMailer.greeting.deliver_now
    @posts = Post.where(user_id: @current_user.id)
  end

  def show
    @post = Post.find_by(id: params[:id])
  end

  def new
    @post = Post.new
  end

  def create
    @post = Post.new(content: params[:content], study_time: params[:'study_time'], today_study_time: params[:'study_time'], hash_tag: params[:hash_tag], user_id: @current_user.id)
    if @post.save
      # flash[:notice] = "保存完了"
      redirect_to("/posts/#{@post.id}")
    else
      # flash[:notice] = "保存失敗"
      render ("posts/new")
    end
  end

  def edit_form
    @post = Post.find_by(id: params[:id])
  end

  def edit
    @post = Post.find_by(id: params[:id])
    @post.content = params[:content]
    @post.hash_tag = params[:hash_tag]
    @post.save
    redirect_to("/posts/#{@post.id}")
  end

  def achievement
    @post = Post.find_by(id: params[:id])

  end

  def destroy
    @post = Post.find_by(id: params[:id])
    @post.destroy
    redirect_to("/posts/index/#{@post.user_id}")
  end

  def update
    @post = Post.find_by(id: params[:id])
    # 本当は下記見たいにしたいけどエラー出る。
    # 原因は@post.study_timeが数値でparams[:study_time]が文字列になってしまっているから
    @post.today_study_time = params[:study_time].to_f
    @post.save
    @post.study_time += @post.today_study_time
    @post.save
    redirect_to("/posts/#{@post.id}")
  end

  def tweet_content
    @post = Post.find_by(id: params[:id])
  end
end
  • アプリ名/app/mailersのapplication_mailer.rb
class ApplicationMailer < ActionMailer::Base
  default from: 'from@example.com'
  layout 'mailer'
end
  • アプリ名/app/views/notice_mailerのgreeting.html.erb
<h1>Notice#greeting</h1>

<p>
  <%= @greeting %>, find me in app/views/notice_mailer/greeting.html.erb
</p>
  • アプリ名/app/views/notice_mailerのgreeting.text.erb
Notice#greeting

<%= @greeting %>, find me in app/views/notice_mailer/greeting.text.erb
  • アプリ名/test/mailersのnotice_mailer_test.rb
require 'test_helper'

class NoticeMailerTest < ActionMailer::TestCase
  test "greeting" do
    mail = NoticeMailer.greeting
    assert_equal "Greeting", mail.subject
    assert_equal ["to@example.org"], mail.to
    assert_equal ["from@example.com"], mail.from
    assert_match "Hi", mail.body.encoded
  end

end
  • アプリ名/test/mailers/previewsのnotice_mailer_preview.rb
# Preview all emails at http://localhost:3000/rails/mailers/notice_mailer
class NoticeMailerPreview < ActionMailer::Preview

  # Preview this email at http://localhost:3000/rails/mailers/notice_mailer/greeting
  def greeting
    NoticeMailer.greeting
  end

end
  • Gemfile
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '2.5.0'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 6.0.0'
# Use sqlite3 as the database for Active Record
# gem 'sqlite3', '~> 1.4'
# Use Puma as the app server
gem 'puma', '~> 3.12'
# Use SCSS for stylesheets
gem 'sass-rails', '~> 5'
# Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker
gem 'webpacker', '~> 4.0'
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
gem 'turbolinks', '~> 5'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.7'
# Use Redis adapter to run Action Cable in production
# gem 'redis', '~> 4.0'
# Use Active Model has_secure_password
gem 'bcrypt', '~> 3.1.7'

# Use Active Storage variant
# gem 'image_processing', '~> 1.2'

# Reduces boot times through caching; required in config/boot.rb
gem 'bootsnap', '>= 1.4.2', require: false

group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
end

group :development do
  # Access an interactive console on exception pages or by calling 'console' anywhere in the code.
  gem 'web-console', '>= 3.3.0'
  gem 'listen', '>= 3.0.5', '< 3.2'
  # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
  gem 'spring'
  gem 'spring-watcher-listen', '~> 2.0.0'
end

group :test do
  # Adds support for Capybara system testing and selenium driver
  gem 'capybara', '>= 2.15'
  gem 'selenium-webdriver'
  # Easy installation and use of web drivers to run system tests with browsers
  gem 'webdrivers'
end

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

gem 'bootstrap', '~> 4.1.1'
gem 'jquery-rails'

gem 'mysql2'

#gem 'bcrypt'
12
8
0

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
12
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?