Action Mailer

Ruby on RailsではAction Mailerを使ってSMTPPOP3と簡単に遣り取りすることができます。
そのAction Mailerを使ってメーラを作ってみましょう。

1.プロジェクトproj003の生成
NetBeansで[新規プロジェクト]を選択

  [ステップ1]プロジェクトを選択
   カテゴリ(C):Ruby
   プロジェクト(P):Ruby on Railsアプリケーション

  [ステップ2]名前と場所
   プロジェクト名(N):proj003
   プロジェクトの場所(I):D:\Rails_Projects
   プロジェクトフォルダ(D):D:\Rails_projects\proj003
   Rubyプラットフォーム(P):Ruby 1.8.7.p72
   サーバー(S): WEBrick

  [ステップ3]データベース構成
   データベースアダプタ(P):mysql
   データベース名(D):proj003_development
   ユーザー名(M):root
   パスワード(W):********

  [ステップ4]Railsのインストール
   Railsのバージョン:2.2.2


2.日本語環境の設定
(1) /config/environment.rbの編集
(2) /app/controllers/application.rbの編集


3.データベースの作成
NetBeansで[Rakeタスクを実行]を選択
  フィルタ(F):
  パラメータ(P):
  一致するタスク(M):db:create

実行結果

(in D:/Rails_Projects/proj003)

4.テーブルpageの作成
(1) モデルの作成
NetBeansで[生成]を選択
  ジェネレータ(G):model
  引数(A):Page

実行結果

exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/page.rb
create test/unit/page_test.rb
create test/fixtures/pages.yml
create db/migrate
create db/migrate/20090929012621_create_pages.rb


(2) マイグレーションファイルの修正

/db/migrate/20090929012621_create_pages.rb

class CreatePages < ActiveRecord::Migration
def self.up
create_table :pages do |t|
t.column :address, :string
t.timestamps
end
end

def self.down
drop_table :pages
end
end



(3) マイグレーションファイルの実行
NetBeansで[データベースマイグレーション]→[現在のバージョンへ]を選択

実行結果

(in D:/Rails_Projects/proj003)
== CreatePages: migrating ====================================================
-- create_table(:pages)
-> 0.0940s
== CreatePages: migrated (0.0940s) ===========================================


5.テーブルemailの作成
(1) モデルの作成
NetBeansで[生成]を選択
  ジェネレータ(G):model
  引数(A):Email

実行結果

exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/email.rb
create test/unit/email_test.rb
create test/fixtures/emails.yml
exists db/migrate
create db/migrate/20090929014002_create_emails.rb


(2) マイグレーションファイルの修正

/db/migrate/20090929014002_create_emails.rb

class CreateEmails < ActiveRecord::Migration
def self.up
create_table :emails do |t|

t.column :page_id, :integer
t.column :subject, :string
t.column :receivedate, :timestamps
t.column :header, :text
t.column :body, :text

t.timestamps
end
end

def self.down
drop_table :emails
end
end



(3) マイグレーションファイルの実行
NetBeansで[データベースマイグレーション]→[現在のバージョンへ]を選択

実行結果

(in D:/Rails_Projects/proj003)
== CreateEmails: migrating ===================================================
-- create_table(:emails)
-> 0.1250s
== CreateEmails: migrated (0.1250s) ==========================================


6.テーブルattachmentの作成
(1) モデルの作成
NetBeansで[生成]を選択
  ジェネレータ(G):model
  引数(A):Attachment

実行結果

exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/attachment.rb
create test/unit/attachment_test.rb
create test/fixtures/attachments.yml
exists db/migrate
create db/migrate/20090929014430_create_attachments.rb


(2) マイグレーションファイルの修正

/db/migrate/20090929014430_create_attachments.rb

class CreateAttachments < ActiveRecord::Migration
def self.up
create_table :attachments do |t|

t.column :page_id, :integer
t.column :file, :binary
t.column :filename, :string
t.column :description, :string

t.timestamps
end
end

def self.down
drop_table :attachments
end
end


(3) マイグレーションファイルの実行
NetBeansで[データベースマイグレーション]→[現在のバージョンへ]を選択

実行結果

(in D:/Rails_Projects/proj003)
== CreateAttachments: migrating ==============================================
-- create_table(:attachments)
-> 0.0940s
== CreateAttachments: migrated (0.0940s) =====================================


7.リレーションの宣言

/app/models/page.rb

class Page < ActiveRecord::Base
has_many :emails
has_many :attachments

end


8.メール受信専用モデルの作成
NetBeansで[生成]を選択
  ジェネレータ(G):mailer
  引数(A):Mailreceiver

実行結果

exists app/models/
create app/views/mailreceiver
exists test/unit/
create test/fixtures/mailreceiver
create app/models/mailreceiver.rb
create test/unit/mailreceiver_test.rb


9.メール受信専用モデルの編集

/app/models/mailreceiver.rb

require 'net/pop'
class Mailreceiver < ActionMailer::Base

@address = 'POP3saver'   # <= 自分のPOP3サーバー
@port = 110 # <= ポート番号 110など
@id = 'userid' # <= ユーザーID
@pass = 'password' # <= パスワード

def receive(email)
page = Page.find_by_address(email.from.first) ||
Page.create(:address => email.from.first)
str = email.subject.kconv(Kconv::UTF8, Kconv::JIS) # JIS から UTF8 に変換
page.emails.create(
:subject => str,
:body => email.body,
:header => email.header,
:messageid => email.message_id,
:receivedate => email.date
)

if email.has_attachments?
for attachment in email.attachments
str = attachment.original_filename.kconv(Kconv::UTF8, Kconv::JIS) # JIS から UTF8 に変換
page.attachments.create({
:file => attachment,
:description => email.subject,
:filename => str
})
end
end
end

def Mailreciiver.r_m
pop = Net::POP3.new(@address, @port)
pop.start(@id, @pass)
if !pop.mails.empty? then
pop.each_mail do |m|
receive(m.pop) # 受信したメールを、「処理」する(DBへ登録)
m.delete # 受信したメールをサーバから削除
end
end
pop.finish
end
end



10.動作確認

コマンド プロンプト

D:Rails_Projects\proj003>ruby script/runner Mailreceiver.r_m
D:Rails_Projects\proj003>


11.メール送信サーバの設定

/config/environments/development.rb

# Settings specified here will take precedence over those in config/environment.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 webserver when you make code changes.
config.cache_classes = false

# Log error messages when you accidentally call methods on nil.
config.whiny_nils = true

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

# Don't care if the mailer can't send

config.action_mailer.raise_delivery_errors = true

config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
:address => 'SMTPsever', # <= 自分のSMTPサーバー
:port => 25, # <= ポート番号 25,587など
:authentication => :login, # <= 認証方法 :plain, :login, :cram_md5など
:user_name => "username", # <= ユーザーID
:password => "password", # <= パスワード
:domain => "domain" # <= ドメイン
}



12.メール送信専用モデルの作成
NetBeansで[生成]を選択
  ジェネレータ(G):mailer
  引数(A):Mailsender

実行結果

exists app/models/
create app/views/mailsender
exists test/unit/
create test/fixtures/mailsender
create app/models/mailsender.rb
create test/unit/mailsender_test.rb


13.メール送信専用モデルの修正

/app/models/mailsender.rb

class Mailsender < ActionMailer::Base
@@default_charset = 'iso-2022-jp'

def okuru(okuru)
str = okuru[:subject].kconv(Kconv::JIS, Kconv::UTF8) # UTF8 から JIS に変換
@subject = str
@recipients = okuru[:to]
@from = okuru[:from]
@sent_on = Time.now
str = okuru[:body].kconv(Kconv::JIS, Kconv::UTF8) # UTF8 から JIS に変換
@body = str
@headers["reply-to"] = okuru[:from]
end

end



14.コントローラrmailerの作成
NetBeansで生成を選択
  ジェネレート(G):controller
  名前(N):rmailer
  ビュー(V):list show new okuru ukeru

実行結果

exists app/controllers/
exists app/helpers/
create app/views/rmailer
exists test/functional/
create app/controllers/rmailer_controller.rb
create test/functional/rmailer_controller_test.rb
create app/helpers/rmailer_helper.rb
create app/views/rmailer/list.html.erb
create app/views/rmailer/show.html.erb
create app/views/rmailer/new.html.erb


15.コントローラrmailer_controllerの編集

/app/controllers/rmailler_controller.rb

class RmailerController < ApplicationController
layout "rmailer"

def list
@emails = Email.find(:all)
end

def show
@email = Email.find(params[:id])
end

def new
end

def okuru
@okuru = params[:okuru]
logger.info "EMAIL:" + params[:okuru][:to]
Mailsender.deliver_okuru(@okuru)

end

def ukeru
job = open('|ruby script/runner Mailreceiver.r_m')
end

end



16.送信用メールフォームの作成

/app/views/rmailer/new.html.erb

<br>
<div class="box">
<%= link_to "受信箱", :action => "list" %>
</div>
<br>
<h1>新規送信メール</h1>
<% form_for(:okuru, :url =>{:action => "okuru"}) do |f| %>
<%= error_messages_for('okuru') %>
<table width="60%">
<tr><th>subject</th><td><%= f.text_field(:subject, :size => 60 ) %></td></tr>
<tr><th>to</th><td><%= f.text_field(:to, :size => 60 ) %></td></tr>
<tr><th>from</th><td><%= f.text_field(:from, :size => 60 ) %></td></tr>
<tr><th>body</th><td><%= f.text_area(:body, :cols => 50, :rows => 10 ) %></td></tr>
<tr><th></th><td><%= submit_tag("送信") %>
</table>
<% end %>


17.送信完了通知の作成

/app/views/rmailer/okuru.html.erb

<br>
<div class="box">
<%= link_to "受信箱", :action => "list" %>
</div>
<br>
<P>送信終了しました</p>


18.受信完了通知の作成

/app/views/rmailer/ukeru.html.erb

<br>
<div class="box">
<%= link_to "受信箱", :action => "list" %>
</div>
<br>
<P>受信終了しました</p>


19.受信箱の作成

/app/views/rmailer/list.html.erb

<br>
<div class="box">
<%= link_to "新規送信", :action => "new" %>
<%= link_to "受信", :action => "ukeru" %>
</div>
<br>
<h1>受信箱</h1>
<table>
<thead>
<tr>
<th>subject</th>
<th>address</th>
<th>receivedate</th>
<th></th>
</tr>
</thead>
<tbody>
<%-
fg = "ON"
@emails.each do |e|
@page = Page.find(e.page_id)
if fg=="ON" then
fg = "off"
-%>
<tr>
<%-
else
fg = "ON"
-%>
<tr class="odd">
<%- end -%>
<td><%=h e.subject %></td>
<td><%=h @page.address %></d>
<td><%=h e.receivedate %></td>
<td><%= link_to "show", :action => "show", :id => e.id %></td>
</tr>
<% end %>
</tbody>
</table>


20.受信メール表示の作成

/app/views/rmailer/show.html.erb

<br>
<div class="box">
<%= link_to "受信箱", :action => "list" %>
</div>
<br>
<h1>受信メール</h1>
<% @page = Page.find(@email.page_id) %>
<table width="60%">
<tr><th>subject</th><td><%=h @email.subject %></td></tr>
<tr><th>address</th><td><%=h @page.address %></td></tr>
<tr><th>receivedate</th><td>%=h @email.receivedate %></td></tr>
<tr><th>body</th><td><%=h @email.body %></td></tr>
</table>


21.スタイルシートの作成
(1) CSSで使用する画像の準備
  /public/images/に透過のtable-back.gifを用意します。
  これは見出し部分を立体的に見せる工夫で背景色より薄めの色で枠線を作ります。
    



(2) IE対応
  IE6.0ではtr:hoverが動作しません。
  http://www.xs4all.nl/~peterned/csshover.htmlからcsshover.htcをダウンロードします。
  ダウンロードしたファイルをcsshover3.htcとリネームして/public/stylesheets/に保存します。


(3) CSSファイルの作成

/public/stylesheets/rmailer.css

/* 見出しを作る */
h1 {
padding: 10px;
border: medium solid #5C443A;
color: #5C443A;
font-family: sans-serif;
}


/* 文字に背景色を付ける */
.box a {
text-decoration: none; /* 下線を消す */
background-color: #cdcdcd; /* 背景色を薄い灰色 */
color: #000000; /* 文字を黒色 */
padding: 4px 10px 2px 10px;
}
.box a:link { /* 未訪問のリンク */
background-color: #cdcdcd; /* 背景色を薄い灰色 */
color: #000000; /* 文字を黒色 */
}
.box a:visited { /* 訪問済みのリンク */
background-color: #cdcdcd; /* 背景色を薄い灰色 */
color: #000000; /* 文字を黒色 */
}
.box a:hover { /* マウスがのっているとき */
background-color: #808080; /* 背景色を濃い灰色 */
color: #ffffff; /* 文字を白色 */
}
.box a:active { /* クリック時のリンク */
background-color: #808080; /* 背景色を濃い灰色 */
color: #ffff00; /* 文字を黄色 */
}

/* テーブル行に背景色を付ける */
body {
behavior: url(/stylesheets/csshover3.htc);
}

table {
border-top:1px solid #5C443A;
border-left:1px solid #5C443A;
border-collapse:collapse;
background:#ffffff;
font-size:90%;
}
caption {
color:#5C443A;
font-weight:bold;
text-align:center;
text-transform: uppercase;
}
thead th, tfoot th, tfoot td {
border-right:1px solid #5C443A;
border-bottom:1px solid #5C443A;
background:#5C443A;
color:#ffffff;
background-image:url(/images/table-back.gif);
background-position:left top;
padding:3px 10px 3px 10px;
text-align:center;
}
td, th {
padding:4px;
}
tbody tr th, tbody tr td {
border-right:1px solid #5C443A;
border-bottom:1px solid #5C443A;
}
tbody tr:hover td, tbody tr:hover th {
background: #996633;
color: #ffffff;
}
tbody tr:hover td a, tbody tr:hover th a {
background: #996633;
color: #ffffff;
}
tbody td a, tbody th a {
border: none;
background: transparent;
color: #000000;
text-decoration: none;
}
tbody td a:hover, tbody th a:hover {
background: #996633;
color: #ffffff;
text-decoration: underline;
}
.odd {
background: #ffeebb;
}



22.レイアウトファイルの作成

/app/views/layouts/rmailer.html.erb

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"
xml:lang="ja" lang="ja">
<head>
<meta http-equiv="Content-Type"
content="text/html; charset=utf-8"/>
<title>Rmailer></title>l;
<%= stylesheet_link_tag 'rmailer' %>
</head>
<body>

<%= yield %>

</body>
</html>


23.動作確認
(1) ブラウザよりhttp://127.0.0.1:3000/list/による起動
    

(2) 受信メール表示
    

(3) 新規送信