Railsでメール送信機能を実装する手順を結構丁寧に(development環境編)

次からもっとスムースにできるように、ここに執筆します。

# 前提

- バージョンは `Rails 5.2.3` です。
- テンプレートエンジンはHamlを使っていますが、ERBでもSlimでもそんなに変わらないはずです。

```
$ rails -v
Rails 5.2.3
```

# 要件(仕様、やりたいこと)

- 問い合わせフォームで必要事項を入力して送信すると、その内容をDBに保存するとともに、管理者にテキストメールで通知する。

# letter_opener を導入する

- [letter_opener](https://github.com/ryanb/letter_opener) というgemを導入すると、開発中にテストで送信したメールが実際にアドレス先に飛んでいく代わりに、ブラウザのポップアップで確認できるようになります。
- 導入することで、テスト用のメールが誤って実際に使われているアドレス先に送信されるのを防ぐことができます。
- 実際にやってみればどうなるかわかると思いますので、とりあえず以下の手順で導入だけ済ませておきます。

```ruby:Gemfile
group :development do
  gem 'letter_opener'
end
```

```
$ bundle install
```

```config/environments/development.rb
config.action_mailer.delivery_method = :letter_opener
```

# 実装

では実装していきます。

## `config/environments/development.rb` を編集する

- `config.action_mailer.raise_delivery_errors = false` をコメントアウトすることで、development環境からもメールを送信する設定に切り替えることができます。
- `config.action_mailer.delivery_method` は先ほど追加した部分です。
- `config.action_mailer.default_url_options` は、後述のメールテンプレート内でURLヘルパーを使用できるようにする設定です。

```config/environments/development.rb
Rails.application.configure do

  #...(中略)...

  # コメントアウトすることでdevelopment環境からもメールを送信する設定になる
  # config.action_mailer.raise_delivery_errors = false

  # smtpで実際にメール送信させるのではなく、letter_openerというgemを用いてテストする
  # config.action_mailer.delivery_method = :smtp
  config.action_mailer.delivery_method = :letter_opener

  # メールテンプレートはviewと違ってURLヘルパーを使ってもドメインが取得できず、メール本文にURLを載せられないので、その対策をする
  config.action_mailer.default_url_options = {:host => 'localhost:3000'}
end
```

## メーラークラスを作成する

- `rails generate` コマンドが使用できます。
- 今回はHTMLメールではなくテキストメールを実装したいため、`app/views/notice_mailer/sendmail_contact.html.haml` は削除します(HTMLテンプレートの方が優先して呼ばれるみたいなので、そちらを残しておくとエラーになったり意図しない内容のメールになってしまいます)。

```
$ rails g mailer Notice sendmail_contact
Running via Spring preloader in process 1180
      create  app/mailers/notice_mailer.rb
      invoke  haml
      create    app/views/notice_mailer
      create    app/views/layouts/mailer.text.haml
      create    app/views/layouts/mailer.html.haml
      create    app/views/notice_mailer/sendmail_contact.text.haml
      create    app/views/notice_mailer/sendmail_contact.html.haml ->削除する
```

- メーラークラスは以下の内容にします。
- 送信元アドレスは実際に存在しないアドレスでも構いません。ここに入れたアドレスが実際に送られるメールのfromに入ってきます。
- 送信先アドレスには実際に送りたいアドレスを指定します。当然ですが存在するアドレスを入れる必要があります(以下のコードでは例として `admin@example.com` を入れています)

```app/mailers/notice_mailer.rb
class NoticeMailer < ApplicationMailer

  # メール送信元アドレスを設定する
  default from: "noreply@example.com"

  def sendmail_contact(contact)
    @contact = contact
    # メール送信先アドレスを設定する
    mail to: "admin@example.com",
         subject: "お問い合わせが届きました"  # メール件名
  end

end
```

## メールテンプレートを作成する

- ここに記述した内容がメール本文になります。
- メーラークラスのメソッド内で使用したインスタンス変数は、ここで参照できます。
- バックスラッシュを使うことで、改行できます。
- 先述した通り、`config/environments/development.rb` に必要な設定をしていれば、URLヘルパーを使うこともできます。

```app/views/notice_mailer/sendmail_contact.text.haml
お問い合わせが届きました。
\
= "会社名: #{@contact.company}"
= "お名前: #{@contact.name}"
= "メールアドレス: #{@contact.email}"
= "電話番号: #{@contact.telephone}"
お問い合わせ内容:
= @contact.message
```

## メーラークラスのメソッドを呼び出す

- 追加しているのは、`NoticeMailer.sendmail_contact(@contact).deliver` の1行です。

```app/controllers/contacts_controller.rb
class ContactsController < ApplicationController

  def new
    @contact = Contact.new
  end

  def create
    @contact = Contact.new(contact_params)
    if @contact.save
      NoticeMailer.sendmail_contact(@contact).deliver # ここで呼び出している
      redirect_to new_contact_url, notice: '問い合わせの送信に成功しました。'
    else
      render :new
    end
  end

  private

  def contact_params
    params.require(:contact).permit(:company, :name, :email, :telephone, :message)
  end

end
```

これで一通りの実装が完了しました。実際に動かしてみましょう！

# (option)development環境から実際にメール送信する

- letter_opener を使わず、実際にメールを送信してみる場合は、`config/environments/development.rb` を以下のように記述します。
- 今回は、ドメインはGmailのものを設定します。
- Gmailのアプリパスワードというのは、普段Googleのアカウントにログインするために使っているパスワードとは異なりますので、ご注意ください。

```config/environments/development.rb
Rails.application.configure do

  #...(中略)...

  # コメントアウトすることでdevelop環境からもメールを送信する設定になる
  # config.action_mailer.raise_delivery_errors = false

  # smtpで実際にメール送信させる
  config.action_mailer.delivery_method = :smtp
  # config.action_mailer.delivery_method = :letter_opener

  # メールテンプレートはviewと違ってURLヘルパーを使ってもドメインが取得できず、メール本文にURLを載せられないので、その対策をする
  config.action_mailer.default_url_options = {:host => 'localhost:3000'}

  config.action_mailer.smtp_settings = {
      :enable_starttls_auto => true,
      :address => 'smtp.gmail.com',
      :port => 587,
      :domain => 'gmail.com',
      :authentication => :plain,
      # 本当に飛ばす場合(letter_openerを使わない場合)は、Gmailのメールアドレスが必要
      :user_name => 'aaaaa@gmail.com',
      # 本当に飛ばす場合(letter_openerを使わない場合)は、Gmailのアプリパスワードが必要
      :password => 'aaaabbbbccccdddd'
  }
end
```

## 追記：機密情報の記述について

アプリパスワードなどの機密情報の記述について、別記事にまとめましたので、ぜひご覧ください。

- [credentials.yml.enc を使ってGmailのアプリパスワードを安全に管理する](https://qiita.com/Tsubasa_Shida/items/804ed86f6dc5cbf5cdd9)

# (WIP)production環境から実際にメール送信する

- 本番環境については別記事にまとめる予定です。まだ私も実装できていないので…。

# 参考

- [開発中にいちいちメールが飛ぶのがウザいとお思いのあなたへーletter_opener - リア充爆発日記](http://ria10.hatenablog.com/entry/20130411/1365680522)
- [メール送信 - 気にすんな - アットウィキ](https://w.atwiki.jp/eyes_33/pages/58.html)
- [Ruby on Rails 4 - メール機能でホストの情報がうまく伝えられない。｜teratail](https://teratail.com/questions/50272?sip=n0070000_019)
- [[Ruby on Rails][Haml] text mail 内で改行するにはバックスラッシュを使う | CodeNote](https://codenote.net/ruby/rails/1815.html)