Net::SMTPAuthenticationError: 530-5.7.0 Authentication Requiredのエラー対処法

この記事はプログラミング学習者がアプリ開発中に躓いた内容を備忘録として記事におこしたものです。内容に不備などあればご指摘頂けると助かります。

## 記事投稿の背景
Xのクローンサイトを制作している時に通知機能の実装で色々と躓いたので、知識整理も兼ねて記事として残すことにしました。

## 遭遇したエラーメッセージ
```ruby:エラーメッセージ
== Preparing database ==
rails aborted!
Net::SMTPAuthenticationError: 530-5.7.0 Authentication Required. For more information, go to
/myapp/db/seeds.rb:159:in `find_or_create_user'
/myapp/db/seeds.rb:167:in `<main>'
```

このエラーメッセージは、SMTPサーバーが認証を要求しているにも関わらず、適切な認証情報が提供されていないためにメールの送信ができないことを示しています。
私の場合、このエラーはGithub Actions中に発生しました。
seeds.rbにメール送信機構を持った通知機能を実装しているのですが、そのコードを検証中に発生したエラーです。

```ruby:seeds.rb
ActionMailer::Base.deliveries.clear if defined?(ActionMailer::Base)

def find_or_create_user(email, phone_number, birthday)
  User.find_by(email:) || User.create!(email:, phone_number:, birthday:,
                                       password: 'password')  # 159行目
end

def find_or_create_tweet(content, user)
  Tweet.find_by(content:, user:) || Tweet.create!(content:, user:)
end

user1 = find_or_create_user('sample@gmail.com', '050-1234-5678', '2000-01-01')  # 167行目
tweet1 = find_or_create_tweet('You are fired.', user1)

favorite1 = Favorite.create!(
  tweet_id: tweet1.id,
  user_id: user1.id
)
if (Rails.env.production? || Rails.env.development?) && !ENV['CI']
  favorite1.tweet.create_notification_favorite!(favorite1.user)
end

user2 = find_or_create_user('apprentice@gmail.com', '070-1234-5678', '2000-12-01')
tweet2 = find_or_create_tweet('Enough!!', user2)

favorite2 = Favorite.create!(
  tweet_id: tweet2.id,
  user_id: user2.id
)
if (Rails.env.production? || Rails.env.development?) && !ENV['CI']
  favorite2.tweet.create_notification_favorite!(favorite2.user)
end

user3 = find_or_create_user('rookie@gmail.com', '080-1234-5678', '2002-12-01')
tweet3 = find_or_create_tweet("I'm done.", user3)

retweet1 = Retweet.create!(
  tweet_id: tweet3.id,
  user_id: user3.id
)
if (Rails.env.production? || Rails.env.development?) && !ENV['CI']
  retweet1.tweet.create_notification_retweet!(retweet1.user)
end

user4 = find_or_create_user('newface@gmail.com', '090-1234-5678', '2012-12-01')
tweet4 = find_or_create_tweet('You are welcome.', user4)

retweet2 = Retweet.create!(
  tweet_id: tweet4.id,
  user_id: user4.id
)
if (Rails.env.production? || Rails.env.development?) && !ENV['CI']
  retweet2.tweet.create_notification_retweet!(retweet2.user)
end

```
メール送信機能を含む通知機能を実装した部分
```ruby:tweet.rb
  def create_notification_favorite!(current_user)
    temp = Notification.where(['visitor_id = ? and visited_id = ? and tweet_id = ? and action = ? ', current_user.id, user_id, id, 'favorite'])
    return if temp.present?

    notification = current_user.active_notifications.new(
      tweet_id: id,
      visited_id: user_id,,
      action: 'favorite'
    )
    # 自分の投稿に対するいいねの場合は、通知済みとする
    notification.checked = true if notification.visitor_id == notification.visited_id
    notification.save if notification.valid?
    # メール送信するメソッドにつながる部分
    NotificationMailer.send_notification(notification, User.find(user_id), current_user).deliver_now
  end

  def create_notification_retweet!(current_user)
    # 既に「リツイート」されているか検索
    temp = Notification.where(['visitor_id = ? and visited_id = ? and tweet_id = ? and action = ?', current_user.id, user_id, id, 'retweet'])
    # リツイートされていない場合のみ通知レコードを生成
    return if temp.present?

    notification = current_user.active_notifications.new(
      tweet_id: id,
      visited_id: user_id,
      action: 'retweet'
    )
    # 自分の投稿に対するリツイートの場合は通知済みとする
    notification.checked = true if notification.visitor_id == notification.visited_id
    notification.save if notification.valid?
    # メール送信するメソッドにつながる部分
    NotificationMailer.send_notification(notification, User.find(user_id), current_user).deliver_now
  end
```
実際にメール送信機能を処理しているActionMailerの設定
```ruby:notification_mailer.rb
class NotificationMailer < ApplicationMailer
  def send_notification(notification, user, current_user)
    @visitor = current_user
    @notification = notification
    @user = user
    mail to: user.email, subject: '弊社サービスからのお知らせ'
  end
end
```

## 解決方法
エラー当初はGithub Actions内の処理が原因だと踏んで`environments/test.rb`の設定だけを修正して再度トライという流れを繰り返していました。
が、手を尽くしてもtest.rbの修正ではエラー解決に至りませんでした。
視点を変えて、他の環境でメール送信できていないのが原因ではないかと推測しました。
思いついた時点でのdevelopment.rbは以下の通りです。
```ruby:developmen.rb - 変更前
  config.action_mailer.delivery_method = :smtp

  config.action_mailer.smtp_settings = {
    address: 'smtp.gmail.com',
    domain: 'gmail.com',
    port: 587,
    user_name: ENV['GMAIL_USERNAME'],
    password: ENV['GMAIL_PASSWORD'],
    authentication: :login
  }
```

試しに認証情報を外して、メールの送信はsmtpからletter opener webで確認するように変更してみました。
```ruby:development.rb - 変更後
  config.action_mailer.delivery_method = :letter_opener_web
```
この変更をすることでエラーを解決することができました。

letter opener webとは
開発環境で使用するためのgemです。
デフォルトのブラウザでRuby on Railsの開発環境から送信処理したメールを閲覧することができます。このgemを導入することで開発環境でのメール送信設定が不要となります。実際にはメールを送信してはいないので、誤ってメールを相手に送信してしまうこともありません。
Railsサーバーが起動した状態で`http://localhost:3000/letter_opener/`にアクセスすれば開発環境で送信処理されたメールの内容を閲覧することができます。
また、letter opener webを利用する為の設定として上のコードで説明した`development.rb`以外に下記のコードを追記する必要があります。
```ruby:routes.rb
mount LetterOpenerWeb::Engine, at: "/letter_opener" if Rails.env.development?
```

蛇足ですが、認証情報のuser_nameやpasswordをハードコード(直接入力)すればエラーが解消されることもあるそうです(特に環境変数がらみのエラー)。但し、環境変数を使用せずに直接秘匿情報を入力することはお勧めできないので、一時的な確認をする程度にとどめておくのが吉かと思います。

## 参考にしたサイト
[gem letter_opener を試してみる](https://qiita.com/sazumy/items/c6193c4c2c352ac152ec)
[Net::SMTPAuthenticationError: 530-5.7.0 Authentication Required Rails Mailer using environmental variable on config](https://stackoverflow.com/questions/59350335/netsmtpauthenticationerror-530-5-7-0-authentication-required-rails-mailer-usi)
[letter_opener_web
](https://github.com/fgrehm/letter_opener_web)