Rails – Gửi email

2.2/5 - (15 votes)

Rails có sẵn một số lớp hỗ trợ gửi email, chúng ta sẽ tìm hiểu cách sử dụng các lớp này.

Chúng ta sẽ gửi mail thông báo xác nhận đã nhận được đơn hàng do người dùng đặt, bạn có thể sử dụng mail server của riêng mình hoặc có thể sử dụng dịch vụ mail nào khác đều được, ở đây mình sẽ sử dụng GMail cho đơn giản.

Có một lưu ý là vào năm 2014 Google đã quyết định khóa tính năng thao tác với email thông qua các ứng dụng kém bảo mật, do đó bạn phải truy cập vào https://www.google.com/settings/security/lesssecureapps và click chọn Turn on để cho phép các ứng dụng bên ngoài có thể truy cập từ xa được, ngoài ra nếu tài khoản của bạn có sử dụng xác thực 2 bước thì bạn cũng phải tắt tính năng này đi mới sử dụng được.

Cấu hình email

Thao tác cấu hình cũng không có gì nhiều để làm, trong thư mục config/environments có 3 file là development.rb, test.rbproduction.rb dùng để khai báo cấu hình tương ứng với từng môi trường mà chúng ta đã tìm hiểu. Chúng ta đang cấu hình cho môi trường phát triển nên sửa lại file development.rb như sau:

Rails.application.configure do
    # Settings specified here will take precedence over those in config/application.rb.

    # In the development environment your application's code is reloaded on
    # every request. This slows down response time but is perfect for development
    # since you don't have to restart the web server when you make code changes.
    config.cache_classes = false

    # Do not eager load code on boot.
    config.eager_load = false

    # Show full error reports and disable caching.
    config.consider_all_requests_local = true
    config.action_controller.perform_caching = false

    # Don't care if the mailer can't send.
    config.action_mailer.raise_delivery_errors = false

    # Print deprecation notices to the Rails logger.
    config.active_support.deprecation = :log

    # Raise an error on page load if there are pending migrations.
    config.active_record.migration_error = :page_load

    # Debug mode disables concatenation and preprocessing of assets.
    # This option may cause significant delays in view rendering with a large
    # number of complex assets.
    config.assets.debug = true

    # Asset digests allow you to set far-future HTTP expiration dates on all assets,
    # yet still be able to expire them through the digest params.
    config.assets.digest = true

    # Adds additional error checking when serving assets at runtime.
    # Checks for improperly declared sprockets dependencies.
    # Raises helpful error messages.
    config.assets.raise_runtime_errors = true

    # Raises error for missing translations
    # config.action_view.raise_on_missing_translations = true
 
    config.action_mailer.delivery_method = :smtp
 
    config.action_mailer.smtp_settings = {
        :address => 'smtp.gmail.com',
        :port => 587,
        :domain => 'phocode.com',
        :authentication => 'plain',
        :user_name => 'phocode7@gmail.com',
        :password => '<mật khẩu>',
        :enable_starttls_auto => true
    }
end

Việc gửi mail sẽ sử dụng phương thức SMTP, các thông số khác như địa chỉ server, port... của GMail là smtp.gmail.com trên cổng 587

Tạo ActionMailer

Đầu tiên chúng ta chạy lệnh rails generate mailer như sau:

C:\Projects\Rails\depot>rails generate mailer Notifier order_received
...

Lệnh trên sẽ tạo một lớp có tên Notifier kế thừa từ lớp ActionMailer::Base, nằm trong file notifier.rb trong thư mục app/mailers. Trong lớp này có phương thức order_received do chúng ta khai báo. Mặc định file này có nội dung như sau:

class Notifier < ApplicationMailer
 
    # Subject can be set in your I18n file at config/locales/en.yml
    # with the following lookup:
    #
    # en.notifier.order_received.subject
    #
    def order_received
        @greeting = "Hi"   
 
        mail to: "to@example.org"
    end
end

Chúng ta chỉnh sửa lại một chút như sau:

class Notifier < ApplicationMailer
    default :from => "Pho Code <phocode7@gmail.com>"

    def order_received(order)    
        @order = order
 
        mail :to => @order.email, :subject => "We've received your order" 
    end
end

Chúng ta cho phương thức này nhận vào tham số là một đối tượng Order vì chỉ có lớp này mới lưu các thông tin về người đặt hàng.

Phương thức mail sẽ thực sự thực hiện việc gửi email, phương thức này nhận vào các tham số:

  • to: địa chỉ người nhận
  • from: địa chỉ người gửi
  • subject: tiêu đề
  • cc: Carbon copy (không bắt buộc)

Tuy nhiên ở đây chúng ta chỉ truyền vào 2 tham số là tosubject thôi, còn from thì chúng ta khai báo là ở dòng default :from... ở đầu file. Ý nghĩa của dòng này là bất kỳ phương thức mail nào cũng sẽ sử dụng tham số :from được khai báo trong dòng default.

Mail Template

Tuy nhiên bạn sẽ nhận ra thành phần còn thiếu đó là nội dung mail. Nội dung sẽ nằm trong file có tên order_received.text.erb hoặc order_received.html.erb trong thư mục app/views/notifier, 2 file này được tạo tự động khi chúng ta chạy lệnh rails generate mailer.

Các file này cũng được gọi là file template giống như Controller thì có View vậy, chỉ khác là ở đây các file này dùng để hiển thị nội dung cho email. File có đuôi .text.erb dùng để hiển thị email dạng text, tức là không thể dùng các thẻ HTML để làm cho có màu mè được.

Mặc định thì Rails sẽ sử dụng template trong file .html.erb.

Chúng ta sửa lại file order_received.html.erb như sau:

<h3>Books Store</h3>
<p>
    Dear <b><%= @order.name %></b>,
</p>

<p>
    Thank you for your order, your items:
</p>
<table>
    <tr>
        <th colspan="2">Quantity</th>
        <th>Description</th>
    </tr>
    <%= render @order.line_items %>
</table>

<p>Your payment type: <b><%= @order.pay_type %></b></p>
<p>Thanks for shopping with <b>Books Store<b> and best regards.</p>

Chúng ta có thể gọi các hàm helper, gọi hàm render như bình thường.

Gửi email

Chúng ta sẽ cho gửi email khi người dùng tạo Order thành công, do đó chúng ta sửa lại phương thức create trong lớp OrdersController như sau:

class OrdersController < ApplicationController 
    .
    .
    .
    # POST /orders
    # POST /orders.json
    def create
        @order = Order.new(order_params)
        @order.add_line_items_from_cart(current_cart)
 
        respond_to do |format|
            if @order.save
                Cart.destroy(session[:cart_id])
                session[:cart_id] = nil
                Notifier.order_received(@order).deliver
 
                format.html { redirect_to '/', notice: 'Thank you for your order' }
                format.json { render :show, status: :created, location: @order }
            else
                format.html { render :new }
                format.json { render json: @order.errors, status: :unprocessable_entity }
            end
        end
    end
    .
    .
    .
end

Để thực hiện việc gửi mail thì chúng ta gọi phương thức order_received() đã định nghĩa ở trên, sau đó gọi phương thức deliver().

Vậy là xong, bây giờ mỗi khi người dùng đặt hàng thì sẽ có mail gửi tới người dùng đó.

mailer

5 1 vote
Article Rating
Subscribe
Thông báo cho tôi qua email khi
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

5 Comments
Inline Feedbacks
View all comments
Kiều Thị Ánh
Kiều Thị Ánh
6 năm trước

Ad cho em hỏi, gửi email thì có phải đăng kí hay làm gì không ạ?
Em làm như bị lỗi này ạ:
530-5.5.1 Authentication Required. Learn more at
Em cảm ơn ad ạ.

Kiều Thị Ánh
Kiều Thị Ánh
6 năm trước
Reply to  Phở Code

Dạ vâng ạ! Em cảm ơn ad ạ.

Kiều Thị Ánh
Kiều Thị Ánh
6 năm trước

Em sửa được rồi ạ. Em cảm ơn ad ạ.