この記事はプログラミング学習者がアプリ開発中に躓いた内容を備忘録として記事におこしたものです。内容に不備などあればご指摘頂けると助かります。
記事投稿の背景
Xのクローンサイトを制作している時に通知機能の実装で色々と躓いたので、知識整理も兼ねて記事として残すことにしました。
遭遇したエラーメッセージ
== 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にメール送信機構を持った通知機能を実装しているのですが、そのコードを検証中に発生したエラーです。
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
メール送信機能を含む通知機能を実装した部分
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の設定
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は以下の通りです。
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で確認するように変更してみました。
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
以外に下記のコードを追記する必要があります。
mount LetterOpenerWeb::Engine, at: "/letter_opener" if Rails.env.development?
蛇足ですが、認証情報のuser_nameやpasswordをハードコード(直接入力)すればエラーが解消されることもあるそうです(特に環境変数がらみのエラー)。但し、環境変数を使用せずに直接秘匿情報を入力することはお勧めできないので、一時的な確認をする程度にとどめておくのが吉かと思います。
参考にしたサイト
gem letter_opener を試してみる
Net::SMTPAuthenticationError: 530-5.7.0 Authentication Required Rails Mailer using environmental variable on config
letter_opener_web