Creating Mail System with Mailgun

Mailgun là một hệ thống các API mạnh mẽ, hỗ trợ việc gửi, nhận và quản lý các email từ hệ thống của bạn cho tới các email được gửi từ các dịch vụ email khác. Trong bài viết này, chúng ta sẽ xây dựng một thệ thống email nội bộ dựa trên một số tính năng mà Mailgun cung cấp.

Tạo tài khoản và cấu hình Mailgun

Chúng ta vào địa chỉ của mailgun và đi đến đường dẫn này để tạo cho mình một tài khoản. Sau khi điền đầy đủ các thông tin cần thiết, Mailgun sẽ gửi một email xác nhận. Việc tiếp theo tất nhiên sẽ là kiểm tra email và làm theo hướng dẫn để kích hoạt tài khoản Mailgun.

Sau khi đã kích hoạt tài khoản và đăng nhập thành công, chúng ta sẽ được chuyển đến trang quản trị của Mailgun. Mặc định Mailgun cung cấp cho chúng ta một domain để hỗ trợ cho việc test trong quá trình phát triển. Nếu như đã có một server SMTP riêng, chúng ta hoàn toàn có thể tạo mới hoặc thay thế domain mặc định đó.

Hệ thống mail sẽ được xây dựng dựa trên ý tưởng lưu lại toàn bộ những email gửi đi cũng như các email từ các hệ thống khác gửi về. Việc lưu các email gửi đi từ hệ thống đơn giản chỉ là việc tạo mới một bản ghi trong bảng email. Vậy còn chiều ngược lại, khi có một email từ bên ngoài gửi về, làm cách nào chúng ta có thể lưu nó lại trong hệ thống của mình? Với Routes của Mailgun, chúng ta đã có giải pháp cho vấn đề đó. Mỗi một route sẽ giống như một bộ lọc, chức năng chính của nó là chuyển tiếp (Forward) các email mà nó nhận được (Catch All) đến một địa chỉ email hay một url nào đó hoặc đơn giản là chẳng làm gì cả nếu như bạn coi đó là một email rác.

Chúng ta vào đường dẫn này để tạo mới một route. Trong màn hình tạo mới route có 3 trường quan trọng nhất mà chúng ta cần lưu ý:

  • Expression Type: Là bộ lọc xác định một email là hợp lệ hay không.
  • Actions: Hành động sẽ được thực hiện khi một email gửi đến là phù hợp với bộ lọc ở trên. Mặc định, email sẽ được chuyển tiếp vào url mà chúng ta chỉ định trong trường Forward.
  • Priority: Trong trường hợp chúng ta có nhiều route và một email có thể là hợp lệ với nhiều route trong số đó thì đây là thuộc tính để xác định xem email đó sẽ được ưu tiên xử lý ở route nào trước.

Như vậy chúng ta đã hoàn thành xong việc cấu hình Mailgun, việc còn lại là xây dựng hệ thống email của riêng mình

Xây dựng hệ thống email

Trong phần này, chúng ta sẽ sử dụng framework Ruby on Rails để minh họa cho việc thực hiện.

1. Lưu trữ email

Tạo bảng email có các trường to, cc, bcc, subject…Các trường của bảng này là tùy thuộc vào mục đích của hệ thống hướng đến nhưng phải luôn đảm bảo được tính bảo mật và dễ dàng xác định được người gửi, người nhận vào loại email tương ứng.

Người dùng trong hệ thống sẽ có một email riêng có dạng abc@yourdomain.com. Phải chắc chắn là chúng ta đã đăng ký domain của mình trong phần Domain trên Maingun.

2. Gửi mail qua Mailgun

Mặc định ActionMailer của Rails sử dụng deliver_method:smpt, để sử dụng với Mailgun, chúng ta cần sửa lại config như sau:

config.action_mailer.delivery_method = :mailgun
config.action_mailer.mailgun_settings = {
  api_key: ENV["MAILGUN_API_KEY"],
  domain: ENV["MAILGUN_DOMAIN"],
}

Để thuận lợi cho việc gửi và lưu lại email, chúng ta tạo ra một class để thực hiện công việc này:

class UserMailer < ActionMailer::Base
  def send_mail email
     mail to: email.to, subject: email.subject
     email.save
  end
end

Chúng ta tạo ra một object email tương ứng với các thông tin mà người dùng mong muốn, email này sẽ được tự động lưu lại ngay sau khi nó được gửi đi.

3. Nhận mail về hệ thống

Khi có một email nào đó gửi đến một địa chỉ có dạng abc@yourdomain.com, Mailgun sẽ bắt được nó thông qua bộ lọc mà chúng ta đã thiết lập, sau đó nó sẽ lựa chọn các action tương ứng. Trong trường hợp này, email sẽ được forward về một url trỏ đến một controller mà chúng ta đã xác định từ trước. Tại đây email sẽ được xử lý và lưu vào database.

Để có thể test được trong quá trình phát triển, chúng ta sẽ phải sử dụng ngrok để public địa chỉ local ra bên ngoài, địa chỉ đó thường có dạng http://872f67bd.ngrok.io. Cùng với đó chúng ta sẽ sử dụng domain mặc định mà Mailgun đã tạo ra sau khi đăng ký tài khoản. Domain này thường có dạng sandbox123xyz.mailgun.org. Đến đây, chúng ta đã có thể dùng email cá nhân để gửi một email vào địa chỉ bất kỳ, giải sử đó là abc@sandbox123xyz.mailgun.org

Sau khi nhận được email, Mailgun sẽ tạo một request với method là POST tới url mà chúng ta đã định nghĩa.

Trong trường hợp này chúng ta muốn Mailgun gửi request về cho EmailsController thì trong phần fowards địa chỉ url sẽ là http://872f67bd.ngrok.io/emails

class EmailsController < ApplicationController
  def create
    ReceiveEmailFromMailgun.new(params).perform
  end
end

Service ReceiveEmailFromMailgun sẽ có nhiệm vụ nhận xử lý params được gửi tử Mailgun và lưu email vào trong hệ thống.

class ReceiveEmailFromMailgun
  def initialize params
    @params = params
  end

  def perform
    ActiveRecord::Base.transaction do
      users.each { |user| clone_email user }
    end
    true
  rescue
    false
  end

  private
  attr_reader :params

  def clone_email user
    email = user.emails.build email_params(user)
    if email.valid?
      email.update_attribute :attachments, email_attachments
    else
      raise ActiveRecord::Invalid
    end
  end

  def users
    @users ||= User.where email: email_to
  end

  def email_to
    params[:recipient].split(",").map(&:strip)
  end

  def email_cc
    return unless params[:Cc].present?
    params[:Cc].split(",").map { |email| email.scan(/<(.+)>/) }.flatten
  end

  def email_attachments
    params.values_at *params.keys.select{ |key| key.match /attachment-[0-9]/ }
  end

  def email_params user
    {
      to: [user.email],
      cc: email_cc,
      from: params[:sender],
      subject: params[:subject],
      info: params[:"body-plain"],
      created_at: params[:Date]
    }
  end
end

Các trường có trong params mà Mailgun gửi về, chúng ta có thể tìm hiểu thêm tại đây. Dựa vào đây chúng ta có thể lấy ra những thông tin cần thiết. Nói qua một chút về chức năng của service ReceiveEmailFromMailgun, method email_to, email_cc, email_attachments tương ứng sẽ lấy ra một mảng địa chỉ to, ccattachments. Từ địa chỉ tocc chúng ta có thể xác định được email này đang muốn gửi tới cho user nào. Tới đây chúng ta thực hiện lưu lại email tương ứng với từng user được tìm thấy.

Conclusion

Như vậy chúng ta đã cùng nhau đi tìm hiểu về cách sử dụng Mailgun để xây dựng hệ thống gửi nhận mail cho riêng mình. Tùy vào chức năng và yêu cầu của từng hệ thống mà cấu trúc cũng như các phương pháp được sử dụng có thể sẽ khác nhau. Bài viết giới thiệu một số trong rất nhiều các chức năng mạnh mẽ mà Mailgun cung cấp. Hi vọng nó sẽ hữu ích khi bạn cần xây dựng một hệ thống email mà bạn có thể chủ động trong việc quản lý nó.