Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
February 21, 2022 09:11 am GMT

Action mailer : a tutorial

Article originally published here : https://www.bootrails.com/blog/action-mailer-tutorial/

Motivation

Action Mailer is already included in any new Rails application. However in this tutorial we will take time to see how each piece of code works. In development, test and production mode. Thus, we hope to increase confidence, and remove any bug fear of any newcomer to the stack.

Prerequisites

Here are the tools we will use in this tutorial :

$> ruby -v  ruby 3.1.0p0 // you need at least version 3 here  $> bundle -v  Bundler version 2.2.11  $> npm -v  8.3.0 // you need at least version 7.1 here  $> yarn -v  1.22.10$> psql --version  psql (PostgreSQL) 13.1 // let's use a production-ready database locally  $> redis-cli ping // redis is a dependency of SidekiqPONG$> foreman -v0.87.2

Create a minimalistic, empty Rails app

By default, a Rails application already embeds Action Mailer, but for this tutorial, this is something we precisely want to build without help. Rails offers a --minimal option that allows the developer to get the bare minimum files for a Rails app, see this article : https://www.bootrails.com/blog/rails-new-options/

Also by default, Rails offers no route, no view, no controller, so here are the commands to create a --minimal Rails app with at least one welcome page that works :

mkdir railsmails && cd railsmails  echo "source 'https://rubygems.org'" > Gemfile  echo "gem 'rails', '~> 7.0.0'" >> Gemfile  bundle install  bundle exec rails new . --force -d=postgresql --minimal# Create a default controllerecho "class WelcomeController < ApplicationController" > app/controllers/welcome_controller.rbecho "end" >> app/controllers/welcome_controller.rb# Create a default routeecho "Rails.application.routes.draw do" > config/routes.rbecho '  get "welcome/index"' >> config/routes.rbecho '  root to: "welcome#index"' >> config/routes.rbecho 'end' >> config/routes.rb# Create a default viewmkdir app/views/welcomeecho '<h1>This is h1 title</h1>' > app/views/welcome/index.html.erb# Create database and schema.rbbin/rails db:createbin/rails db:migrate

First step : require ActionMailer in the application

Open application.rb and uncomment line with action_mailer as follow :

# inside config/application.rbrequire_relative "boot"require "rails"# Pick the frameworks you want:require "active_model/railtie"# require "active_job/railtie"require "active_record/railtie"# require "active_storage/engine"require "action_controller/railtie"require "action_mailer/railtie" #  Uncomment# ... everything else remains the same

Create ApplicationMailer, our base Class

# inside app/mailers/application_mailer.rbclass ApplicationMailer < ActionMailer::Base  default from: "[email protected]"  layout "mailer"end

Ok ! Very interesting here.

  • We guess that the sender is "from@example" by default, which is 1) not the address we want and 2) we probably don't want it to be public anyway. So a good place would be to put it inside a .env file.
  • A layout is needed, just like plain Rails Views.
  • Last but not least, by integrating ourself this base class, we are now aware of pieces of configuration, that our mind would have skipped if the app was built "as usual" (i.e. without the --minimal flag)

Create classic layout

Create app/views/layouts/mailer.html.erb

<!-- inside app/views/layouts/mailer.html.erb --><!DOCTYPE html><html>  <head>    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />    <style>      /* Email styles need to be inline */    </style>  </head>  <body>    <%= yield %>  </body></html>

Development mode

In development, you don't want any real e-mail to go out of the application, this might be too dangerous.

To avoid this, add the letter_opener gem to your Gemfile. Any email sent will then just be a file written on your local disk, that will be displayed instantly in the browser, once the email is sent.

# inside Gemfilegem 'letter_opener', group: :development

Then run

bundle install

Then configure config/environments/development.rb by adding the following few lines :

# inside config/environments/development.rb# ...  config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }  config.action_mailer.delivery_method = :letter_opener  config.action_mailer.perform_deliveries = true # ...

Now make possible for the app to send an email :

# inside app/mailers/hello_mailer.rbclass HelloMailer < ApplicationMailer  default from: '[email protected]'  def welcome_email    @user = params[:user]    mail(to: @user[:email], subject: 'Welcome to My Awesome Site')  endend

Side notes :

  • mail will actually deliver the email, it comes from the inherited ApplicationMailer.
  • The e-mail will be sent from '[email protected]' as stated in the 2nd line

Now create a file welcome_email.html.erb inside app/views/hello_mailer :

<!-- inside app/views/hello_mailer/welcome_email.html.erb --><!DOCTYPE html><html>  <head>    <meta content='text/html; charset=UTF-8' http-equiv='Content-Type' />  </head>  <body>    <h1>Welcome to example.com, <%= @user[:name] %></h1>    <p>Thanks for joining and have a great day!</p>  </body></html>

Now you can send the email from anywhere in your application. Let's see how.

# inside config/routes.rbRails.application.routes.draw do  get "welcome/index"  # route where you will send an email  post "welcome/please_send_email"  # where visitor are redirected once email has been sent  get "welcome/email_sent"  root to: "welcome#index"end
# inside app/controllers/welcome_controller.rbclass WelcomeController < ApplicationController  def index  end  def please_send_email    HelloMailer.with(user: {name: 'jane', email: '[email protected]'}).welcome_email.deliver_later  end  def email_sent  endend

Side notes :

  • Here we use OpenStruct to mimic a Ruby Object
  • deliver_later allows us to send email in the background, in development or test mode, email will be send immediately, but we need a 3rd party tool like Sidekiq to take care of background jobs in production, see this article : https://www.bootrails.com/blog/rails-sidekiq-tutorial/

Now build the views

<%# inside app/views/welcome/index.html.erb %><h1>This is h1 title</h1><%= form_with url: welcome_please_send_email_path do |f| %> <%= f.submit 'Send e-mail' %><% end %>
<%# inside app/views/welcome/email_sent.html.erb %><h1>We tried to send an email</h1><p>Please check the logs</p>

Launch your local web server by running :

$> bin/rails s

The following screen should be displayed :

localhost

localhost

Now click the button, an email should be shown in a new tab :

new tab

new tab

Check the logs in the console :

Processing by WelcomeController#email_sent as HTML  Rendering layout layouts/application.html.erb  Rendering welcome/email_sent.html.erb within layouts/application[ActiveJob] [ActionMailer::MailDeliveryJob] [bf93f412-257e-4e17-8b0d-67316f95362a]   Rendered layout layouts/mailer.html.erb (Duration: 3.4ms | Allocations: 1274)  Rendered welcome/email_sent.html.erb within layouts/application (Duration: 2.1ms | Allocations: 407)  Rendered layout layouts/application.html.erb (Duration: 11.3ms | Allocations: 4630)Completed 200 OK in 14ms (Views: 13.4ms | ActiveRecord: 0.0ms | Allocations: 5658)[ActiveJob] [ActionMailer::MailDeliveryJob] [bf93f412-257e-4e17-8b0d-67316f95362a] HelloMailer#welcome_email: processed outbound mail in 289.8ms[ActiveJob] [ActionMailer::MailDeliveryJob] [bf93f412-257e-4e17-8b0d-67316f95362a] Delivered mail [email protected] (61.7ms)[ActiveJob] [ActionMailer::MailDeliveryJob] [bf93f412-257e-4e17-8b0d-67316f95362a] Date: Sun, 13 Feb 2022 11:54:14 +0100From: [email protected]: [email protected]: <[email protected]>Subject: Welcome to My Awesome SiteMime-Version: 1.0Content-Type: text/html; charset=UTF-8Content-Transfer-Encoding: 7bit

Great ! We're now able to send e-mail in development mode.

Test mode

Now the tricky part. In test mode,

  • you don't want real e-mails to be sent,
  • you also don't want e-mails to be displayed in the browser like in dev mode,
  • you don't want e-mails to stay forever in the job queue

To avoid all this, open config/environments/test.rb :
Add these 3 lines at the bottom of the file

  config.action_mailer.default_url_options = { host: 'localhost', port: 5100 }  config.action_mailer.delivery_method = :test  config.active_job.queue_adapter = :test

default_url_options actual values don't really matter in test mode, but be aware that in production, you need to add the actual domain here in the host key.

Now google around to see where to put perform_enqueued_jobs in your test - you could wrap your test around this block, or simply call ActiveJob::Base.queue_adapter.perform_enqueued_jobs = true before your test suite.

Then, in your test, all you have to do to read the body of the last received email is something like this :

ActionMailer::Base.deliveries.try(:last).try(:body).try(:decoded)

Production

In production, in order to send real e-mail to real people, you need a 3rd party tool like Mandrill, MailChimp or PostMark.

The steps are as follow :

  • So subscribe to any of these 3rd party provider, they generally have a large generous free tier, and anyway sending e-mail will not work at scale with free e-mail provider like Gmail (this is not recommended to try)

  • Install the corresponding Ruby gem

  • Follow docs to get the API key, and configure your Rails app as stated in the docs

Here are the step for PostMark : https://postmarkapp.com/send-email/rails

Warning ! The PostMark tutorial wants you to modify config/application.rb, which is not a good idea : the config will apply to dev and test mode. Instead, put the configuration inside config/environments/production.rb

That's it

Sending email with Rails is not complicated, but you have to take care of each 3 environments separately: development, test, and production. 3 environments, 3 different ways to handle emails. With this in mind, and a slow but well-understood first installation, you should not encounter any problem when dealing with emails.

Enjoy !


Original Link: https://dev.to/bdavidxyz/action-mailer-a-tutorial-gfd

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To