---
# System prepended metadata

title: '[Rails4][mailer]用內建mailer發送郵件:使用hostinger'
tags: [Rails4, mailer]

---

# [Rails4][mailer]用內建mailer發送郵件:使用hostinger

###### tags: `Rails4`,`mailer`

>ruby: 2.2.6
>rails: 4.2.8
>
參考資料:
https://railsbook.tw/chapters/20-send-email.html
https://railsbook.tw/chapters/21-background-job.html
https://stackoverflow.com/questions/48970619/rails-delayed-job-is-using-a-different-time-zone
https://ihower.tw/rails/actionmailer.html



>本文假設已有hostinger的帳號並有開通相關smtp設定
>hostinger是一個國外知名的網路主機供應商
>主頁:
>https://hpanel.hostinger.com/
>啟用smtp:
>https://www.hostinger.com/how-to/how-can-i-enable-smtp-authentication

## 新建專案

```c!
$ rails new rails_mailer -d postgresql
$ cd rails_mailer
$ rake db:setup
$ bundle
$ rails s
```

## mailer

### 1.新增Contact_mailer
```c!
$ rails g mailer Contact
```

### 2.編輯application_mailer
app/mailers/application_mailer.rb
```ruby
class ApplicationMailer < ActionMailer::Base
  default from: "urmailaccounts@urdomain" #<--編輯此行
  layout 'mailer'
end
```

### 3.編輯contact.rb
app/mailers/contact.rb
```ruby
class Contact < ApplicationMailer
  def say_hello(address="clouderstorage@gmail.com")
    mail to: address,subject:"這是一封測試郵件"
  end
end
```
>Rails 4.2版的mailer用cmd產生時,似乎不會在檔名後面加上_mailer
>

### 4.新增say_hello.html.erb
app/views/contact/say_hello.html.erb
```ruby
<h2>這是一封測試信</h2>
```

## 修改發信設定
參考:
https://ihower.tw/rails/actionmailer.html

### 1.修改development.rb
config/environments/development.rb
```ruby!
Rails.application.configure do
#...
  config.action_mailer.delivery_method = :smtp
  config.action_mailer.default_url_options = { host: "http://localhost:3000" }
  config.action_mailer.smtp_settings = config_for(:email).symbolize_keys
end
```

### 2.新增email.yml
config/email.yml
```yaml=
development:
  address: "smtp.hostinger.com"
  port: 587
  authentication: "plain"
  user_name: "ur_mail_account@ur_domain"
  password: "ur password"
  enable_starttls_auto: true
  openssl_verify_mode: 'none'
```
>*上面檔案是hostinger的設定,各家mail dsmtp設定不同


## 開啟log顯示(optional)
config/environments/development.rb
```ruby!
Rails.application.configure do
#...

# Don't care if the mailer can't send.
  config.action_mailer.raise_delivery_errors = true #<--把這個改為true
  
```

## 修改config/routes
```ruby
root 'home#index'
```

## home_controller

### 1.新增home_controller
```terminal
$ rails g controller home
```

### 2.修改home_controller
app/controllers/home_controller.rb
```ruby=
class HomeController < ApplicationController
  def index
  end

  #POST home/send_mail
  def send_mail
    Contact.say_hello(params[:email]).deliver_now
    flash[:notice]="email has been sent to #{params[:email]}"
    redirect_to root_path
  end
end
```

## 新增index.html.erb

app/views/home/index.html.erb
```htmlmixed=
<h2>home index</h2>

<% if flash[:notice] %>
  <p><%=flash[:notice]%></p>
<% end %>

<%=form_tag("/home/send_mail") do%>
  <div>email:</div>
  <%= text_field_tag :email, "", class: 'form-control' %>
  <%= submit_tag "send email"%>
<% end %>
```
>1.沒有要寫入資料庫也沒有用到model,使用form_tag直接傳值即可,
>不使用form_for
>2.input欄位是輸入收件人之用,按下send email後,收件人會收到測試信件


到此,執行rails s,應可正常發送信件


因發送信件需要時間,
實務上有時會將發信的工作在系統較不忙碌時再於背景執行

要在背景執行有兩種做法,delayed_job跟sidekiq,擇一使用即可

## delayed_job

### 安裝 delayed_job_active_record

```c!
$ bundle add 'delayed_job_active_record'
$ rails g delayed_job:active_record
$ rake db:migrate
```

### 修改application.rb

https://stackoverflow.com/questions/48970619/rails-delayed-job-is-using-a-different-time-zone
https://railsbook.tw/chapters/21-background-job.html
config/application.rb

```ruby!
require File.expand_path('../boot', __FILE__)

require 'rails/all'

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module RailsMailer
  class Application < Rails::Application
  ###加上以下內容
    config.active_job.queue_adapter = :delayed_job
    config.active_record.default_timezone = :local #<-加上這句以避免時區問題
  ###加上以上內容
    #...
    config.active_record.raise_in_transactional_callbacks = true
  end
end
```

### 設定jobs
app/jobs/send_test_email_job.rb
```ruby
class SendTestEmailJob < ActiveJob::Base
  queue_as :default

  def perform(email)
    # Do something later
    Contact.say_hello(email).deliver_now
  end
end
```

### 修改home_controller
```ruby!
class HomeController < ApplicationController
  def index
  end

  #POST home/send_mail
  def send_mail
    SendTestEmailJob.perform_later(params[:email]) #<-修改此行
    flash[:notice]="email has been sent to #{params[:email]}"
    redirect_to root_path
  end
end

```

### 自訂路徑設定
https://stackoverflow.com/questions/20396944/rails-custom-delayed-job-uninitialized-constant
config/application.rb
```ruby!
config.autoload_paths += %W(
  #{config.root}/ur/path/to/jobs
)
```



### 執行server
https://stackoverflow.com/questions/28229923/invoke-rake-jobswork-automatically-after-running-rails-s-in-console


```terminal
rails server & rake jobs:work
```
> 必須加上rake jobs:work
才會在背景執行工作

---
## sidekiq
https://ihower.tw/rails/background-process.html
https://www.botreetechnologies.com/blog/migrate-from-delayed-job-to-sidekiq
https://hostpresto.com/community/tutorials/how-to-install-and-configure-redis-on-ubuntu-14-04/

sidekiq與delayed_jobs類似,只是它使用redis做為暫存資料庫.
使用redis不需帳號密碼
(有些檔案與之前的相同未更動,故略過)

### 安裝redis
```c!
$ sudo apt-get update
$ sudo apt-get -y install redis-server
```

### 確認redis已經在運行
```c!
$ sudo service redis-server status
```


### 安裝sidekiq gem
```c!
bundle add sidekiq
```

config/application.rb
```ruby=

require File.expand_path('../boot', __FILE__)

require 'rails/all'

Bundler.require(*Rails.groups)

module RailsMailer
  class Application < Rails::Application
  ###加上以下內容
    config.active_job.queue_adapter = :sidekiq #<-改成使用sidekiq
    config.active_record.default_timezone = :local #<-加上這句以避免時區問題
  ###加上以上內容
    #...
    config.active_record.raise_in_transactional_callbacks = true
  end
end
```

### 設定worker
app/workers/email_sender.rb
```ruby
class EmailSender
  include Sidekiq::Worker

  def perform(email)
    # Do something later
    Contact.say_hello(email).deliver_now
  end
end

```

### 自訂路徑設定
https://stackoverflow.com/questions/20396944/rails-custom-delayed-job-uninitialized-constant
config/application.rb
```ruby!
config.autoload_paths += %W(
  #{config.root}/ur/path/to/workers
)
```

### 修改home_controller
```ruby!
class HomeController < ApplicationController
  def index
  end

  #POST home/send_mail
  def send_mail
  
    # send email using sidekiq
    EmailSender.perform_async(emails,title,content) #<-修改此行
    
    flash[:notice]="email has been sent to #{params[:email]}"
    redirect_to root_path
  end
end
```

## 執行server

先執行sidekiq
```c!
$ sidekiq
```

再開新terminal執行rails server
```c!
$ rails s
```






