rubyonrails.org에서 더 보기:

GitHub에서 이 파일을 읽지 마세요. 가이드는 https://guides.rubyonrails.org에 게시되어 있습니다.

Action Mailer 기초

이 가이드에서는 Rails 애플리케이션에서 이메일을 보내는 방법을 다룹니다.

이 가이드를 읽고 나면 다음과 같은 내용을 알 수 있습니다:

  • Action Mailer 클래스와 mailer view를 생성하고 편집하는 방법
  • 첨부 파일과 멀티파트 이메일을 보내는 방법
  • Action Mailer callback을 사용하는 방법
  • 환경에 맞게 Action Mailer를 구성하는 방법
  • 이메일을 미리보고 Action Mailer 클래스를 테스트하는 방법

1 Action Mailer란?

Action Mailer를 사용하면 Rails 애플리케이션에서 이메일을 보낼 수 있습니다. Rails 프레임워크에서 이메일 관련 두 가지 컴포넌트 중 하나입니다. 다른 하나는 이메일 수신을 다루는 Action Mailbox입니다.

Action Mailer는 클래스("mailer"라고 함)와 view를 사용하여 보낼 이메일을 생성하고 구성합니다. Mailer는 ActionMailer::Base를 상속하는 클래스입니다. Mailer 클래스는 controller 클래스와 유사합니다. 둘 다 다음과 같은 특징이 있습니다:

  • view에서 접근 가능한 인스턴스 변수
  • layout과 partial을 사용할 수 있는 기능
  • params hash에 접근할 수 있는 기능
  • app/views의 action과 연관된 view

2 Mailer와 View 생성하기

이 섹션에서는 Action Mailer로 이메일을 보내는 방법을 단계별로 안내합니다. 각 단계의 세부 사항은 다음과 같습니다.

2.1 Mailer 생성하기

먼저 "mailer" generator를 사용하여 Mailer 관련 클래스를 생성합니다:

$ bin/rails generate mailer User
create  app/mailers/user_mailer.rb
invoke  erb
create    app/views/user_mailer
invoke  test_unit
create    test/mailers/user_mailer_test.rb
create    test/mailers/previews/user_mailer_preview.rb

아래의 UserMailer와 같이, 생성된 모든 Mailer 클래스는 ApplicationMailer를 상속합니다:

# app/mailers/user_mailer.rb
class UserMailer < ApplicationMailer
end

ApplicationMailer 클래스는 ActionMailer::Base를 상속하며, 모든 Mailer에 공통적인 속성을 정의하는데 사용할 수 있습니다:

# app/mailers/application_mailer.rb
class ApplicationMailer < ActionMailer::Base
  default from: "from@example.com"
  layout "mailer"
end

generator를 사용하지 않으려면, app/mailers 디렉토리에 파일을 직접 추가할 수도 있습니다. 클래스가 ApplicationMailer를 상속하는지 확인하세요:

# app/mailers/custom_mailer.rb
class CustomMailer < ApplicationMailer
end

2.2 Mailer 편집하기

app/mailers/user_mailer.rbUserMailer는 처음에는 메서드가 없습니다. 그래서 다음으로, 특정 이메일을 보낼 메서드(즉 action)를 mailer에 추가합니다.

Mailer는 "action"이라고 불리는 메서드를 가지고 있으며, controller와 유사하게 view를 사용하여 컨텐츠를 구성합니다. controller가 클라이언트에게 보낼 HTML 컨텐츠를 생성하는 반면, Mailer는 이메일을 통해 전달할 메시지를 생성합니다.

사용자의 등록된 이메일 주소로 이메일을 보내는 welcome_email이라는 메서드를 UserMailer에 추가해보겠습니다:

class UserMailer < ApplicationMailer
  default from: "notifications@example.com"

  def welcome_email
    @user = params[:user]
    @url  = "http://example.com/login"
    mail(to: @user.email, subject: "Welcome to My Awesome Site")
  end
end

mailer의 메서드 이름이 반드시 _email로 끝날 필요는 없습니다.

위에서 사용된 Mailer 관련 메서드에 대한 간단한 설명입니다:

  • default 메서드는 mailer에서 보내는 모든 이메일에 대한 기본값을 설정합니다. 이 경우에는 이 클래스의 모든 메시지에 대한 :from 헤더 값을 설정하는 데 사용합니다. 이는 각 이메일별로 재정의할 수 있습니다.
  • mail 메서드는 실제 이메일 메시지를 생성합니다. 각 이메일별로 :to:subject 같은 헤더의 값을 지정하는 데 사용합니다.

또한 (위에서는 사용되지 않은) headers 메서드가 있는데, 이는 해시를 사용하거나 headers[:field_name] = 'value'를 호출하여 이메일 헤더를 지정하는 데 사용됩니다.

generator를 사용할 때 다음과 같이 직접 action을 지정하는 것도 가능합니다:

$ bin/rails generate mailer User welcome_email

위 명령은 빈 welcome_email 메서드가 있는 UserMailer를 생성합니다.

하나의 mailer 클래스에서 여러 이메일을 보낼 수도 있습니다. 관련된 이메일들을 함께 그룹화하는 것이 편리할 수 있습니다. 예를 들어, 위의 UserMailerwelcome_email 외에도 goodbye_email(과 해당 view)을 가질 수 있습니다.

2.3 Mailer View 만들기

다음으로, welcome_email action을 위해 app/views/user_mailer/ 디렉토리에 welcome_email.html.erb라는 파일에 매칭되는 view를 만들어야 합니다. 다음은 환영 이메일에 사용할 수 있는 HTML 템플릿 예시입니다:

<h1>example.com에 오신 것을 환영합니다, <%= @user.name %></h1>
<p>
  example.com에 성공적으로 가입하셨습니다,
  회원님의 아이디는: <%= @user.login %>입니다.<br>
</p>
<p>
  사이트에 로그인하시려면 다음 링크를 클릭하세요: <%= link_to '로그인', login_url %>.
</p>
<p>가입해주셔서 감사합니다. 좋은 하루 보내세요!</p>

위 내용은 <body> 태그의 내용입니다. 이는 <html> 태그를 포함하는 기본 mailer 레이아웃에 포함될 것입니다. 자세한 내용은 Mailer 레이아웃을 참조하세요.

위 이메일의 텍스트 버전도 만들 수 있으며 app/views/user_mailer/ 디렉토리에 welcome_email.text.erb로 저장할 수 있습니다(확장자가 html.erb가 아닌 .text.erb임에 주의하세요). HTML 렌더링에 문제가 발생할 경우 텍스트 버전이 신뢰할 수 있는 대체 수단이 될 수 있기 때문에 두 형식을 모두 보내는 것이 모범 사례로 여겨집니다. 다음은 텍스트 이메일의 예시입니다:

example.com에 오신 것을 환영합니다, <%= @user.name %>
===============================================

example.com에 성공적으로 가입하셨습니다,
회원님의 아이디는: <%= @user.login %>입니다.

사이트에 로그인하시려면 다음 링크를 클릭하세요: <%= @url %>.

가입해주셔서 감사합니다. 좋은 하루 보내세요!

HTML과 텍스트 이메일 템플릿 모두에서 인스턴스 변수 @user@url을 사용할 수 있음을 주목하세요.

이제 mail 메서드를 호출하면, Action Mailer가 두 템플릿(텍스트와 HTML)을 감지하여 자동으로 multipart/alternative 이메일을 생성합니다.

2.4 Mailer 호출하기

mailer 클래스와 view를 설정했다면, 다음 단계는 이메일 view를 렌더링하는(즉, 이메일을 보내는) mailer 메서드를 실제로 호출하는 것입니다. Mailer는 view를 렌더링하는 또 다른 방법으로 생각할 수 있습니다. 컨트롤러 액션은 HTTP 프로토콜을 통해 전송될 view를 렌더링합니다. Mailer 액션은 view를 렌더링하여 이메일 프로토콜을 통해 전송합니다.

UserMailer를 사용하여 사용자가 성공적으로 생성되었을 때 환영 이메일을 보내는 예제를 살펴보겠습니다.

먼저, User scaffold를 생성합니다:

$ bin/rails generate scaffold user name email login
$ bin/rails db:migrate

다음으로, 새로운 사용자가 생성되었을 때 환영 이메일을 보내기 위해 UserControllercreate 액션을 수정합니다. 사용자가 성공적으로 저장된 직후에 UserMailer.with(user: @user).welcome_email를 호출하는 코드를 삽입합니다.

이메일을 나중에 보내기 위해 deliver_later를 사용합니다. 이렇게 하면 컨트롤러 액션이 이메일 전송 코드가 실행되기를 기다리지 않고 계속 진행됩니다. deliver_later 메서드는 Active Job에 의해 지원됩니다.

class UsersController < ApplicationController
  # ...

  def create
    @user = User.new(user_params)

    respond_to do |format|
      if @user.save
        # 저장 후 UserMailer에 환영 이메일 전송을 요청
        UserMailer.with(user: @user).welcome_email.deliver_later

        format.html { redirect_to user_url(@user), notice: "User was successfully created." }
        format.json { render :show, status: :created, location: @user }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end

  # ...
end

with에 전달된 모든 키-값 쌍은 Mailer 액션의 params가 됩니다. 예를 들어, with(user: @user, account: @user.account)는 Mailer 액션에서 params[:user]params[:account]를 사용할 수 있게 합니다.

위의 mailer, view, 그리고 컨트롤러 설정으로, 새로운 User를 생성하면,

welcome email이 전송되는 것을 로그에서 확인할 수 있습니다. 로그 파일은 다음과 같이 text와 HTML 버전이 전송되는 것을 보여줍니다:

[ActiveJob] [ActionMailer::MailDeliveryJob] [ec4b3786-b9fc-4b5e-8153-9153095e1cbf] Delivered mail 6661f55087e34_1380c7eb86934d@Bhumis-MacBook-Pro.local.mail (19.9ms)
[ActiveJob] [ActionMailer::MailDeliveryJob] [ec4b3786-b9fc-4b5e-8153-9153095e1cbf] Date: Thu, 06 Jun 2024 12:43:44 -0500
From: notifications@example.com
To: test@gmail.com
Message-ID: <6661f55087e34_1380c7eb86934d@Bhumis-MacBook-Pro.local.mail>
Subject: Welcome to My Awesome Site
Mime-Version: 1.0
Content-Type: multipart/alternative;
 boundary="--==_mimepart_6661f55086194_1380c7eb869259";
 charset=UTF-8
Content-Transfer-Encoding: 7bit


----==_mimepart_6661f55086194_1380c7eb869259
Content-Type: text/plain;

...

----==_mimepart_6661f55086194_1380c7eb869259
Content-Type: text/html;

...

controller 액션을 설정하기 전에 테스트로 유용할 수 있는 Rails console에서 mailer를 호출하고 이메일을 보낼 수도 있습니다. 아래는 위와 동일한 welcome_email을 보낼 것입니다:

irb> user = User.first
irb> UserMailer.with(user: user).welcome_email.deliver_later

이메일을 즉시 보내고 싶다면(예: cronjob에서) deliver_now를 호출할 수 있습니다:

class SendWeeklySummary
  def run
    User.find_each do |user|
      UserMailer.with(user: user).weekly_summary.deliver_now
    end
  end
end

UserMailerweekly_summary와 같은 메서드는 ActionMailer::MessageDelivery 객체를 반환하는데, 이 객체는 지금 또는 나중에 자신을 보내기 위한 deliver_now 또는 deliver_later 메서드를 가지고 있습니다. ActionMailer::MessageDelivery 객체는 Mail::Message 객체의 래퍼입니다. Mail::Message 객체를 검사하거나 수정하거나 다른 작업을 수행하려면 ActionMailer::MessageDelivery 객체의 message 메서드를 통해 접근할 수 있습니다.

다음은 위의 Rails 콘솔 예제에서 MessageDelivery 객체의 예시입니다:

irb> UserMailer.with(user: user).weekly_summary
#<ActionMailer::MailDeliveryJob:0x00007f84cb0367c0
 @_halted_callback_hook_called=nil,
 @_scheduled_at_time=nil,
 @arguments=
  ["UserMailer",
   "welcome_email",
   "deliver_now",
   {:params=>
     {:user=>
       #<User:0x00007f84c9327198
        id: 1,
        name: "Bhumi",
        email: "hi@gmail.com",
        login: "Bhumi",
        created_at: Thu, 06 Jun 2024 17:43:44.424064000 UTC +00:00,
        updated_at: Thu, 06 Jun 2024 17:43:44.424064000 UTC +00:00>},
    :args=>[]}],
 @exception_executions={},
 @executions=0,
 @job_id="07747748-59cc-4e88-812a-0d677040cd5a",
 @priority=nil,

3 Multipart Emails and Attachments

multipart MIME type은 각각 고유한 MIME type(text/htmltext/plain 같은)을 가질 수 있는 여러 구성 요소로 이루어진 문서를 나타냅니다. multipart type은 예를 들어 이메일에 여러 파일을 첨부하는 것처럼 여러 파일을 하나의 트랜잭션으로 함께 전송하는 것을 캡슐화합니다.

3.1 첨부 파일 추가하기

Action Mailer에서는 attachments method에 파일 이름과 내용을 전달하여 첨부 파일을 추가할 수 있습니다. Action Mailer는 자동으로 mime_type을 추측하고, encoding을 설정하며, 첨부 파일을 생성합니다.

attachments["filename.jpg"] = File.read("/path/to/filename.jpg")

mail 메소드가 트리거되면, 첨부 파일이 있는 multipart 이메일을 전송합니다. 최상위 레벨은 multipart/mixed이며 첫 번째 부분은 일반 텍스트와 HTML 이메일 메시지를 포함하는 multipart/alternative로 적절하게 중첩됩니다.

첨부 파일을 보내는 다른 방법은 파일 이름, MIME-type, encoding 헤더, 그리고 내용을 지정하는 것입니다. Action Mailer는 전달된 설정을 사용할 것입니다.

encoded_content = SpecialEncode(File.read("/path/to/filename.jpg"))
attachments["filename.jpg"] = {
  mime_type: "application/gzip",
  encoding: "SpecialEncoding",
  content: encoded_content
}

Action Mailer는 자동으로 첨부 파일을 Base64로 인코딩합니다. 다른 방식을 원한다면, 내용을 직접 인코딩하고 인코딩된 내용과 인코딩 방식을 Hashattachments 메소드에 전달할 수 있습니다. 인코딩을 지정하면, Action Mailer는 첨부 파일을 Base64로 인코딩하지 않습니다.

3.2 인라인 첨부 파일 만들기

때로는 첨부 파일(예: 이미지)을 이메일 본문 내에 인라인으로 표시하고 싶을 수 있습니다.

이를 위해서는 먼저 #inline을 호출하여 첨부 파일을 인라인 첨부 파일로 변환해야 합니다:

def welcome
  attachments.inline["image.jpg"] = File.read("/path/to/image.jpg")
end

그런 다음 view에서 attachments를 hash로 참조하고 inline으로 표시할 파일을 지정할 수 있습니다. hash에서 url을 호출하고 결과를 image_tag 메서드에 전달할 수 있습니다:

<p>Hello there, this is the image you requested:</p>

<%= image_tag attachments['image.jpg'].url %>

이것은 image_tag의 표준 호출이므로 attachment URL 뒤에 options hash도 전달할 수 있습니다:

<p>Hello there, this is our image</p>

<%= image_tag attachments['image.jpg'].url, alt: 'My Photo', class: 'photos' %>

3.3 Multipart Emails

Create a Mailer View에서 설명한 것처럼, 동일한 action에 대해 다른 템플릿이 있는 경우 Action Mailer는 자동으로 multipart 이메일을 보냅니다. 예를 들어, app/views/user_mailerwelcome_email.text.erbwelcome_email.html.erb가 있는 UserMailer가 있다면, Action Mailer는 자동으로 HTML과 텍스트 버전이 별도의 파트로 포함된 multipart 이메일을 보냅니다.

Mail gem은 text/plaintext/html MIME types에 대한 multipart/alternate 이메일을 만드는 helper 메서드를 제공하며, 다른 종류의 MIME 이메일도 수동으로 생성할 수 있습니다.

파트가 삽입되는 순서는 ActionMailer::Base.default 메서드 내의 :parts_order에 의해 결정됩니다.

Multipart는 이메일과 함께 첨부 파일을 보낼 때도 사용됩니다.

4 Mailer Views와 Layouts

Action Mailer는 이메일로 보낼 내용을 지정하기 위해 view 파일을 사용합니다. Mailer view는 기본적으로 app/views/name_of_mailer_class 디렉토리에 위치합니다. Controller view와 마찬가지로 파일 이름은 mailer 메서드의 이름과 일치합니다.

Mailer view는 controller view와 유사하게 layout 내에서 렌더링됩니다. Mailer

layouts는 app/views/layouts에 위치합니다. 기본 layout은 mailer.html.erbmailer.text.erb 입니다. 이 섹션에서는 mailer views와 layouts 관련 다양한 기능들을 다룹니다.

4.1 사용자 정의 View 경로 설정하기

아래와 같이 다양한 방법으로 action에 대한 기본 mailer view를 변경할 수 있습니다.

mail 메서드에는 template_pathtemplate_name 옵션이 있습니다:

class UserMailer < ApplicationMailer
  default from: "notifications@example.com"

  def welcome_email
    @user = params[:user]
    @url  = "http://example.com/login"
    mail(to: @user.email,
         subject: "Welcome to My Awesome Site",
         template_path: "notifications",
         template_name: "hello")
  end
end

위 코드는 mail 메서드가 app/views/notifications 디렉토리에서 hello라는 이름의 template을 찾도록 설정합니다. template_path에 경로 배열을 지정할 수도 있으며, 순서대로 검색됩니다.

더 많은 유연성이 필요한 경우, block을 전달하고 특정 template을 렌더링할 수도 있습니다. template 파일을 사용하지 않고 평문 텍스트를 인라인으로 렌더링할 수도 있습니다:

class UserMailer < ApplicationMailer
  default from: "notifications@example.com"

  def welcome_email
    @user = params[:user]
    @url  = "http://example.com/login"
    mail(to: @user.email,
         subject: "Welcome to My Awesome Site") do |format|
      format.html { render "another_template" }
      format.text { render plain: "hello" }
    end
  end
end

이는 HTML 부분에 대해서는 another_template.html.erb template을 렌더링하고

text 부분에 대해 "hello"를 렌더링합니다. render 메서드는 Action Controller 내부에서 사용되는 것과 동일하므로 :plain, :inline 등과 같은 모든 옵션을 사용할 수 있습니다.

마지막으로, 기본 app/views/mailer_name/ 디렉토리 외부에 있는 템플릿을 렌더링해야 하는 경우 다음과 같이 prepend_view_path를 적용할 수 있습니다:

class UserMailer < ApplicationMailer
  prepend_view_path "custom/path/to/mailer/view"

  # "custom/path/to/mailer/view/welcome_email" 템플릿을 로드하려고 시도합니다
  def welcome_email
    # ...
  end
end

append_view_path 메서드도 있습니다.

4.2 Action Mailer Views에서 URL 생성하기

메일러에 URL을 추가하려면 먼저 애플리케이션의 도메인에 host 값을 설정해야 합니다. 이는 컨트롤러와 달리 메일러 인스턴스가 들어오는 요청에 대한 컨텍스트를 가지고 있지 않기 때문입니다.

config/application.rb에서 애플리케이션 전체의 기본 host를 구성할 수 있습니다:

config.action_mailer.default_url_options = { host: "example.com" }

host가 구성되면, 이메일 뷰에서 상대 URL이 있는 *_path 헬퍼가 아닌 전체 URL이 있는 *_url을 사용하는 것이 좋습니다. 이메일 클라이언트는 웹 요청 컨텍스트가 없기 때문에 *_path 헬퍼는 완전한 웹 주소를 형성할 기본 URL이 없습니다.

예를 들어, 다음과 같이 하지 않고:

<%= link_to 'welcome', welcome_path %>
<%= link_to 'welcome', welcome_url %>

를 사용하면 됩니다.

전체 URL을 사용하면 이메일에서도 링크가 올바르게 작동합니다.

4.2.1 url_for로 URL 생성하기

url_for 헬퍼는 기본적으로 템플릿에서 전체 URL을 생성합니다.

:host 옵션을 전역적으로 설정하지 않은 경우, url_for에 이를 전달해야 합니다.

<%= url_for(host: 'example.com',
            controller: 'welcome',
            action: 'greeting') %>

4.2.2 Named Routes로 URL 생성하기

다른 URL들과 마찬가지로, 이메일에서도 named route 헬퍼의 *_url 변형을 사용해야 합니다.

:host 옵션을 전역적으로 설정하거나 URL 헬퍼에 직접 전달해야 합니다:

<%= user_url(@user, host: 'example.com') %>

4.3 Action Mailer 뷰에 이미지 추가하기

이메일에서 image_tag 헬퍼를 사용하려면 :asset_host 파라미터를 지정해야 합니다. 이는 mailer 인스턴스가 수신 요청에 대한 컨텍스트를 가지고 있지 않기 때문입니다.

일반적으로 :asset_host는 애플리케이션 전체에서 일관되므로, config/application.rb에서 전역적으로 설정할 수 있습니다:

config.action_mailer.asset_host = "http://example.com"

요청으로부터 프로토콜을 유추할 수 없기 때문에, :asset_host config에 http:// 또는 https://와 같은 프로토콜을 명시해야 합니다.

이제 이메일 내에 이미지를 표시할 수 있습니다.

<%= image_tag 'image.jpg' %>

4.4 Mailer View 캐싱하기

애플리케이션 view와 유사하게, cache 메서드를 사용하여 mailer view에서도 fragment 캐싱을 수행할 수 있습니다.

<% cache do %>
  <%= @company.name %>
<% end %>

이 기능을 사용하려면 애플리케이션의 config/environments/*.rb 파일에서 활성화해야 합니다:

config.action_mailer.perform_caching = true

Fragment 캐싱은 multipart 이메일에서도 지원됩니다. 캐싱에 대해 더 자세히 알아보려면 Rails 캐싱 가이드를 참조하세요.

4.5 Action Mailer 레이아웃

컨트롤러 레이아웃과 마찬가지로, mailer 레이아웃도 가질 수 있습니다. Mailer 레이아웃은 app/views/layouts에 위치합니다. 다음은 기본 레이아웃입니다:

# 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>
<%= yield %>
  </body>
</html>

위의 레이아웃은 mailer.html.erb 파일에 있습니다. 기본 레이아웃 이름은 앞서 Generate Mailer 섹션에서 본 layout "mailer" 라인처럼 ApplicationMailer에 지정되어 있습니다. 컨트롤러 레이아웃과 유사하게, yield를 사용하여 레이아웃 안에 mailer view를 렌더링합니다.

특정 mailer에 대해 다른 레이아웃을 사용하려면 layout을 호출하세요:

class UserMailer < ApplicationMailer
  layout "awesome" # awesome.(html|text).erb를 레이아웃으로 사용
end

특정 이메일에 대해 특정 레이아웃을 사용하려면 format 블록 내의 render 호출에 layout: 'layout_name' 옵션을 전달할 수 있습니다:

class UserMailer < ApplicationMailer
  def welcome_email
    mail(to: params[:user].email) do |format|
      format.html { render layout: "my_layout" }
      format.text
    end
  end
end

위의 코드는 HTML 부분을 my_layout.html.erb 파일을 사용하여 렌더링하고, 텍스트 부분은 일반적인 user_mailer.text.erb 파일로 렌더링합니다.

5 이메일 보내기

5.1 여러 수신자에게 이메일 보내기

:to 필드에 이메일 주소 목록을 설정하여 한 명 이상의 수신자에게 이메일을 보낼 수 있습니다. 이메일 목록은 배열이나 쉼표로 구분된 주소가 있는 단일 문자열이 될 수 있습니다.

예를 들어, 모든 관리자에게 새로운 등록을 알리려면:

class AdminMailer < ApplicationMailer
  default to: -> { Admin.pluck(:email) },
          from: "notification@example.com"

  def new_registration(user)
    @user = user
    mail(subject: "New User Signup: #{@user.email}")
  end
end

동일한 형식으로 여러 명의 참조(cc)와 숨은 참조(bcc) 수신인을 추가할 수 있습니다. :cc:bcc 키를 각각 설정하면 됩니다(:to 필드와 유사).

5.2 이름과 함께 이메일 보내기

이메일을 받거나 보내는 사람의 이메일 주소 외에 이름도 표시할 수 있습니다.

이메일을 받는 사람의 이름을 표시하려면 to:에서 email_address_with_name 메서드를 사용할 수 있습니다:

def welcome_email
  @user = params[:user]
  mail(
    to: email_address_with_name(@user.email, @user.name),
    subject: "Welcome to My Awesome Site"
  )
end

from:에서도 동일한 메서드를 사용해 보내는 사람의 이름을 표시할 수 있습니다:

class UserMailer < ApplicationMailer
  default from: email_address_with_name("notification@example.com", "Example Company Notifications")
end

이름이 비어있는 경우(nil 또는 빈 문자열), 이메일 주소만 반환됩니다.

5.3 제목 번역과 함께 이메일 보내기

mail 메서드에 제목을 전달하지 않으면, Action Mailer는 번역에서 제목을 찾으려고 시도합니다. 자세한 내용은 국제화 가이드를 참조하세요.

5.4 템플릿 렌더링 없이 이메일 보내기

템플릿 렌더링 단계를 건너뛰고 대신 이메일 본문을 문자열로 제공하고 싶은 경우가 있을 수 있습니다. :body 옵션을 사용하여 이를 구현할 수 있습니다. :content_type 옵션을 설정하는 것을 잊지 마세요. 아래와 같이 text/html로 설정할 수 있습니다. Rails는 기본적으로 content type을 text/plain으로 설정합니다.

class UserMailer < ApplicationMailer
  def welcome_email
    mail(to: params[:user].email,
         body: params[:email_body],
         content_type: "text/html",
         subject: "Already rendered!")
  end
end

5.5 동적 전송 옵션으로 이메일 보내기

이메일을 전송하는 동안 기본 전송 configuration(예: SMTP 인증 정보)을 재정의하고 싶다면, mailer action에서 delivery_method_options를 사용하여 이를 수행할 수 있습니다.

class UserMailer < ApplicationMailer
  def welcome_email
    @user = params[:user]
    @url  = user_url(@user)
    delivery_options = { user_name: params[:company].smtp_user,
                         password: params[:company].smtp_password,
                         address: params[:company].smtp_host }
    mail(to: @user.email,
         subject: "Please see the Terms and Conditions attached",
         delivery_method_options: delivery_options)
  end
end

6 Action Mailer Callbacks

Action Mailer는 메시지를 구성하기 위한 before_action, after_action, around_action과 전송을 제어하기 위한 before_deliver, after_deliver, around_deliver를 지정할 수 있게 해줍니다.

Callback은 다른 callback들(controller나 model에서처럼)과 유사하게 block이나 mailer 클래스의 메서드 이름을 나타내는 symbol로 지정할 수 있습니다.

다음은 mailer에서 이러한 callback을 사용할 수 있는 예시들입니다.

6.1 before_action

before_action을 사용하여 인스턴스 변수를 설정하거나, mail 객체에 기본값을 채우거나, 기본 헤더와 첨부 파일을 삽입할 수 있습니다.

class InvitationsMailer < ApplicationMailer
  before_action :set_inviter_and_invitee
  before_action { @account = params[:inviter].account }

  default to:       -> { @invitee.email_address },
          from:     -> { common_address(@inviter) },
          reply_to: -> { @inviter.email_address_with_name }

  def account_invitation
    mail subject: "#{@inviter.name} invited you to their Basecamp (#{@account.name})"
  end

  def project_invitation
    @project    = params[:project]
    @summarizer = ProjectInvitationSummarizer.new(@project.bucket)

    mail subject: "#{@inviter.name.familiar} added you to a project in Basecamp (#{@account.name})"
  end

  private
    def set_inviter_and_invitee
      @inviter = params[:inviter]
      @invitee = params[:invitee]
    end
end

6.2 after_action

after_action callback은 before_action과 비슷한 방식으로 설정할 수 있으며, mailer action에서 설정된 인스턴스 변수에도 접근할 수 있습니다.

또한 mail.delivery_method.settings를 업데이트하여 delivery method 설정을 재정의하는 데 after_action을 사용할 수 있습니다.

class UserMailer < ApplicationMailer
  before_action { @business, @user = params[:business], params[:user] }

  after_action :set_delivery_options,
                :prevent_delivery_to_guests, 
                :set_business_headers

  def feedback_message
  end

  def campaign_message  
  end

  private
    def set_delivery_options
      # 여기서 mail 인스턴스,
      # @business와 @user 인스턴스 변수에 접근할 수 있습니다
      if @business && @business.has_smtp_settings?
        mail.delivery_method.settings.merge!(@business.smtp_settings)
      end
    end

    def prevent_delivery_to_guests
      if @user && @user.guest?
        mail.perform_deliveries = false
      end
    end

    def set_business_headers
      if @business
        headers["X-SMTPAPI-CATEGORY"] = @business.code
      end
    end
end

6.3 after_deliver

메시지 전달을 기록하기 위해 after_deliver를 사용할 수 있습니다. 또한 observer/interceptor와 같은 동작을 허용하지만, 전체 mailer 컨텍스트에 접근할 수 있습니다.

class UserMailer < ApplicationMailer
  after_deliver :mark_delivered
  before_deliver :sandbox_staging
  after_deliver :observe_delivery

  def feedback_message
    @feedback = params[:feedback]
  end

  private

    def mark_delivered
      params[:feedback].touch(:delivered_at)
    end

    # Interceptor의 대안
    def sandbox_staging
      message.to = ["sandbox@example.com"] if Rails.env.staging? 
    end

    # callback은 Observer 예제보다 더 많은 컨텍스트를 가집니다.
    def observe_delivery
      EmailDelivery.log(message, self.class, action_name, params)
    end
end

Mailer callback은 body가 nil이 아닌 값으로 설정되면 추가 처리를 중단합니다. before_deliverthrow :abort로 중단할 수 있습니다.

7 Action Mailer View Helper

Action Mailer 뷰는 일반 뷰와 동일한 대부분의 helper에 접근할 수 있습니다.

또한 ActionMailer::MailHelper에서 사용할 수 있는 Action Mailer 전용 helper 메소드도 있습니다. 예를 들어, 뷰에서 mailer를 통해 mailer 인스턴스에 접근하고 message로 메시지에 접근할 수 있습니다:

<%= stylesheet_link_tag mailer.name.underscore %>
<h1><%= message.subject %></h1>

8 Action Mailer 설정

이 섹션에서는 Action Mailer의 몇 가지 예제 설정을 보여줍니다.

다양한 설정 옵션에 대한 자세한 내용은 Rails 애플리케이션 설정하기 가이드를 참조하세요. production.rb와 같은 환경별 파일에 설정 옵션을 지정할 수 있습니다.

8.1 Action Mailer 설정 예제

다음은 config/environments/$RAILS_ENV.rb 파일에 추가된 :sendmail 전송 방법을 사용하는 예제입니다:

config.action_mailer.delivery_method = :sendmail
# 기본값:
# config.action_mailer.sendmail_settings = {
#   location: '/usr/sbin/sendmail',
#   arguments: %w[ -i ]
# }
config.action_mailer.perform_deliveries = true
config.action_mailer.raise_delivery_errors = true
config.action_mailer.default_options = { from: "no-reply@example.com" }

8.2 Gmail을 위한 Action Mailer 설정

Gmail을 통해 메일을 보내기 위해 config/environments/$RAILS_ENV.rb 파일에 다음을 추가하세요:

config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
  address:         "smtp.gmail.com",
  port:            587,
  domain:          "example.com",
  user_name:       Rails.application.credentials.dig(:smtp, :user_name),
  password:        Rails.application.credentials.dig(:smtp, :password),
  authentication:  "plain",
  enable_starttls: true,
  open_timeout:    5,
  read_timeout:    5 }

주의: Google은

Google은 덜 안전하다고 간주되는 앱의 sign-ins을 차단할 수 있습니다. Gmail 설정을 변경하여 이러한 시도를 허용할 수 있습니다. Gmail 계정에 2단계 인증이 활성화되어 있다면, 앱 비밀번호를 설정하고 일반 비밀번호 대신 이를 사용해야 합니다.

9 Mailer 미리보기 및 테스트

테스팅 가이드에서 mailer를 테스트하는 방법에 대한 자세한 설명을 찾을 수 있습니다.

9.1 이메일 미리보기

특별한 Action Mailer 미리보기 URL을 방문하여 렌더링된 이메일 템플릿을 시각적으로 미리볼 수 있습니다. UserMailer의 미리보기를 설정하려면, test/mailers/previews/ 디렉토리에 UserMailerPreview라는 클래스를 생성하세요. UserMailerwelcome_email을 미리보려면, UserMailerPreview에서 동일한 이름의 메서드를 구현하고 UserMailer.welcome_email을 호출하세요:

class UserMailerPreview < ActionMailer::Preview
  def welcome_email
    UserMailer.with(user: User.first).welcome_email
  end
end

이제 미리보기는 http://localhost:3000/rails/mailers/user_mailer/welcome_email에서 확인할 수 있습니다.

app/views/user_mailer/welcome_email.html.erb의 mailer 뷰나 mailer 자체를 변경하면, 미리보기가 자동으로 업데이트됩니다. 미리보기 목록은 http://localhost:3000/rails/mailers에서도 확인할 수 있습니다.

기본적으로, 이러한 미리보기 클래스들은 test/mailers/previews에 위치합니다. 이는 preview_paths 옵션을 사용하여 구성할 수 있습니다. 예를 들어, lib/mailer_previews를 추가하려면 config/application.rb에서 다음과 같이 구성할 수 있습니다:

config.action_mailer.preview_paths << "#{Rails.root}/lib/mailer_previews"

9.2 에러 복구

mailer 메서드 내의 rescue 블록은 렌더링 외부에서 발생하는 에러를 복구할 수 없습니다. 예를 들어, 백그라운드 작업에서의 레코드 역직렬화 에러나 서드파티 메일 전송 서비스의 에러 등이 있습니다.

mailing process 중 발생하는 error를 처리하기 위해 rescue_from을 사용하세요:

class NotifierMailer < ApplicationMailer
  rescue_from ActiveJob::DeserializationError do
    # ...
  end

  rescue_from "SomeThirdPartyService::ApiError" do
    # ...
  end

  def notify(recipient)
    mail(to: recipient, subject: "Notification")
  end
end

10 Email 가로채기와 관찰하기

Action Mailer는 Mail observer와 interceptor 메서드에 대한 hook을 제공합니다. 이를 통해 모든 이메일 전송의 전달 생명주기 동안 호출되는 클래스를 등록할 수 있습니다.

10.1 Email 가로채기

Interceptor를 사용하면 이메일이 전달 에이전트에 전달되기 전에 수정할 수 있습니다. interceptor 클래스는 이메일이 전송되기 전에 호출되는 .delivering_email(message) 메서드를 구현해야 합니다.

class SandboxEmailInterceptor
  def self.delivering_email(message)
    message.to = ["sandbox@example.com"]
  end
end

interceptor는 interceptors config 옵션을 사용하여 등록해야 합니다. 이는 config/initializers/mail_interceptors.rb와 같은 initializer 파일에서 설정할 수 있습니다:

Rails.application.configure do
  if Rails.env.staging?
    config.action_mailer.interceptors = %w[SandboxEmailInterceptor]
  end
end

위 예제는 테스트 목적으로 production과 유사한 서버를 위한 "staging"이라는 커스텀 환경을 사용합니다. 커스텀 Rails 환경에 대한 자세한 내용은 Rails 환경 생성하기에서 확인할 수 있습니다.

10.2 이메일 관찰하기

Observer는 이메일 메시지가 전송된 후에 접근할 수 있게 해줍니다. Observer 클래스는 이메일이 전송된 후 호출될 :delivered_email(message) 메서드를 구현해야 합니다.

class EmailDeliveryObserver
  def self.delivered_email(message)
    EmailDelivery.log(message)
  end
end

Interceptor와 마찬가지로, observer를 observers 설정 옵션을 사용하여 등록해야 합니다. 이는 config/initializers/mail_observers.rb와 같은 initializer 파일에서 할 수 있습니다:

Rails.application.configure do
  config.action_mailer.observers = %w[EmailDeliveryObserver]
end


맨 위로