feat: add Resend email delivery method and configuration (#11)
* feat: add Resend email delivery method and configuration * chore: simplify ResendProvider initialization by removing settings parameter * test: update ResendProvider initialization in tests by removing unnecessary settings parameter * chore: improvements
This commit is contained in:
parent
a9f0dc35f9
commit
5b7fc9ae77
@ -262,3 +262,5 @@ AZURE_APP_SECRET=
|
||||
BAILEYS_PROVIDER_DEFAULT_CLIENT_NAME=Chatwoot
|
||||
BAILEYS_PROVIDER_DEFAULT_URL=http://localhost:3025
|
||||
BAILEYS_PROVIDER_DEFAULT_API_KEY=
|
||||
|
||||
RESEND_API_KEY=
|
||||
|
||||
2
Gemfile
2
Gemfile
@ -178,6 +178,8 @@ gem 'ruby-openai'
|
||||
|
||||
gem 'shopify_api'
|
||||
|
||||
gem 'resend', '~> 0.19.0'
|
||||
|
||||
### Gems required only in specific deployment environments ###
|
||||
##############################################################
|
||||
|
||||
|
||||
@ -634,6 +634,8 @@ GEM
|
||||
uber (< 0.2.0)
|
||||
request_store (1.5.1)
|
||||
rack (>= 1.4)
|
||||
resend (0.19.0)
|
||||
httparty (>= 0.21.0)
|
||||
responders (3.1.1)
|
||||
actionpack (>= 5.2)
|
||||
railties (>= 5.2)
|
||||
@ -957,6 +959,7 @@ DEPENDENCIES
|
||||
rails (~> 7.0.8.4)
|
||||
redis
|
||||
redis-namespace
|
||||
resend (~> 0.19.0)
|
||||
responders (>= 3.1.1)
|
||||
rest-client
|
||||
reverse_markdown
|
||||
|
||||
@ -4,5 +4,7 @@
|
||||
|
||||
<p><%= link_to 'Change my password', frontend_url('auth/password/edit', reset_password_token: @token) %></p>
|
||||
|
||||
<p style="color: #999999; font-size: 12px;">Copy and paste the URL into your browser if the link above doesn't work: <%= frontend_url('auth/password/edit', reset_password_token: @token) %></p>
|
||||
|
||||
<p>If you didn't request this, please ignore this email.</p>
|
||||
<p>Your password won't change until you access the link above and create a new one.</p>
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
require_relative '../../lib/mail/resend_provider'
|
||||
|
||||
Rails.application.configure do
|
||||
#########################################
|
||||
# Configuration Related to Action Mailer
|
||||
@ -36,6 +38,9 @@ Rails.application.configure do
|
||||
# You can use letter opener for your local development by setting the environment variable
|
||||
config.action_mailer.delivery_method = :letter_opener if Rails.env.development? && ENV['LETTER_OPENER']
|
||||
|
||||
config.action_mailer.delivery_method = :resend if ENV['RESEND_API_KEY'].present?
|
||||
ActionMailer::Base.add_delivery_method :resend, Mail::ResendProvider
|
||||
|
||||
#########################################
|
||||
# Configuration Related to Action MailBox
|
||||
#########################################
|
||||
|
||||
3
config/initializers/resend.rb
Normal file
3
config/initializers/resend.rb
Normal file
@ -0,0 +1,3 @@
|
||||
require 'resend'
|
||||
|
||||
Resend.api_key = ENV.fetch('RESEND_API_KEY', nil)
|
||||
29
lib/mail/resend_provider.rb
Normal file
29
lib/mail/resend_provider.rb
Normal file
@ -0,0 +1,29 @@
|
||||
module Mail # rubocop:disable Style/ClassAndModuleChildren
|
||||
class ResendProvider
|
||||
class DeliveryError < StandardError; end
|
||||
|
||||
def initialize(_settings); end # rubocop:disable Style/RedundantInitialize
|
||||
|
||||
def deliver!(mail)
|
||||
Resend::Emails.send(
|
||||
from: mail.smtp_envelope_from,
|
||||
to: mail.smtp_envelope_to,
|
||||
subject: mail.subject,
|
||||
html: mail.decoded,
|
||||
text: sanitize_html(mail.decoded)
|
||||
)
|
||||
rescue Resend::Error => e
|
||||
raise DeliveryError, "Failed to send email: #{e.message}"
|
||||
rescue StandardError => e
|
||||
raise DeliveryError, "An error occurred while sending email: #{e.message}"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def sanitize_html(html)
|
||||
sanitized = ActionView::Base.full_sanitizer.sanitize(html)
|
||||
# NOTE: Remove more than two consecutive newlines
|
||||
sanitized.lines.map(&:strip).join("\n").gsub(/\n{3,}/, "\n\n").strip
|
||||
end
|
||||
end
|
||||
end
|
||||
57
spec/lib/mail/resend_provider_spec.rb
Normal file
57
spec/lib/mail/resend_provider_spec.rb
Normal file
@ -0,0 +1,57 @@
|
||||
require 'rails_helper'
|
||||
|
||||
describe Mail::ResendProvider do
|
||||
let(:provider) { described_class.new({}) }
|
||||
let(:mail) do
|
||||
instance_double(Mail::Message,
|
||||
smtp_envelope_from: 'sender@example.com',
|
||||
smtp_envelope_to: ['receiver@example.com'],
|
||||
subject: 'Test Email',
|
||||
decoded: '<p>This is a test email message.</p>')
|
||||
end
|
||||
|
||||
describe '#deliver!' do
|
||||
it 'calls Resend with the correct parameters' do
|
||||
response = instance_double(HTTParty::Response, success?: true)
|
||||
allow(Resend::Emails).to receive(:send)
|
||||
.with(
|
||||
from: 'sender@example.com',
|
||||
to: ['receiver@example.com'],
|
||||
subject: 'Test Email',
|
||||
html: '<p>This is a test email message.</p>',
|
||||
text: 'This is a test email message.'
|
||||
)
|
||||
.and_return(response)
|
||||
|
||||
provider.deliver!(mail)
|
||||
|
||||
expect(Resend::Emails).to have_received(:send)
|
||||
end
|
||||
|
||||
context 'when response is not successful' do
|
||||
it 'raises a DeliveryError with the error message' do
|
||||
allow(Resend::Emails).to receive(:send)
|
||||
.with(
|
||||
from: 'sender@example.com',
|
||||
to: ['receiver@example.com'],
|
||||
subject: 'Test Email',
|
||||
html: '<p>This is a test email message.</p>',
|
||||
text: 'This is a test email message.'
|
||||
)
|
||||
.and_raise(Resend::Error.new('Service unavailable'))
|
||||
|
||||
expect { provider.deliver!(mail) }
|
||||
.to raise_error(described_class::DeliveryError, 'Failed to send email: Service unavailable')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when an exception occurs during sending' do
|
||||
it 'raises a DeliveryError with the exception message' do
|
||||
allow(Resend::Emails).to receive(:send).and_raise(StandardError, 'Connection timed out')
|
||||
|
||||
expect { provider.deliver!(mail) }
|
||||
.to raise_error(described_class::DeliveryError, 'An error occurred while sending email: Connection timed out')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Reference in New Issue
Block a user