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.rb
의 UserMailer
는 처음에는 메서드가 없습니다. 그래서 다음으로, 특정 이메일을 보낼 메서드(즉 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 클래스에서 여러 이메일을 보낼 수도 있습니다. 관련된 이메일들을 함께 그룹화하는 것이 편리할 수 있습니다. 예를 들어, 위의 UserMailer
는 welcome_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
다음으로, 새로운 사용자가 생성되었을 때 환영 이메일을 보내기 위해 UserController
의 create
액션을 수정합니다. 사용자가 성공적으로 저장된 직후에 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
UserMailer
의 weekly_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/html
과 text/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로 인코딩합니다. 다른 방식을 원한다면, 내용을 직접 인코딩하고 인코딩된 내용과 인코딩 방식을 Hash
로 attachments
메소드에 전달할 수 있습니다. 인코딩을 지정하면, 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_mailer
에 welcome_email.text.erb
와 welcome_email.html.erb
가 있는 UserMailer
가 있다면, Action Mailer는 자동으로 HTML과 텍스트 버전이 별도의 파트로 포함된 multipart 이메일을 보냅니다.
Mail gem은 text/plain
과 text/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.erb
와 mailer.text.erb
입니다. 이 섹션에서는 mailer views와 layouts 관련 다양한 기능들을 다룹니다.
4.1 사용자 정의 View 경로 설정하기
아래와 같이 다양한 방법으로 action에 대한 기본 mailer view를 변경할 수 있습니다.
mail
메서드에는 template_path
와 template_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_deliver
는 throw :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
라는 클래스를 생성하세요. UserMailer
의 welcome_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