ソースコードで学ぶWebプログラミング

[Ruby]お問い合わせフォームの作り方

お問い合わせフォームとは、サイト訪問者がサイト運営者と連絡を取るための窓口となるものです。フォーム画面は、HTMLのフォームタグで構成され、送信されたデータを受け取るWebプログラムが必要となります。今回は、そのデータを受け取るフォーム用プログラムをRuby言語で作成します。

Rubyでお問い合わせフォームを作る方法

お問い合わせフォームには、どのような機能が必要となるか洗い出してみます。まず連絡を取り合うために、フォームから送信者のメールアドレスを受け取れるようにします。また送信先は、プログラム内で設定できるようにします。

1.データ「件名、送信者名、送信者アドレス、本文」を受け取る ・POSTリクエストで受け取る 2.データ「件名、送信者名、送信者アドレス、本文」を送信データに変換する ・送信データは、文字コードISO-2022-JPで送信する ・件名には、日本語を含める ・送信者名には、日本語を含める ・宛先には、日本語を含める 3.送信データを出力する ・指定アドレスに送信する

要件毎に送信するメール文章をテンプレート化しておく方法もありますが、今回は問い合わせのみとして、プログラム内に直接設定する構成にします。

Rubyで同サーバからメールを送信する方法

Rubyで、sendmailコマンドからメールを送信するには、IOモジュールのpopenが利用できます。メールの件名や宛先の名前に日本語を使用したい場合は、nkfモジュールを使用します。

Rubyでは、文字列として変数を展開するには#{}を使用します。また連想配列(ハッシュ)のキーには、通常の文字列の他、シンボルと呼ばれる:の付いた英数字アンダースコアを利用できます。

#!/usr/bin/ruby require 'nkf' # sendmailのパス SENDMAIL = '/usr/sbin/sendmail' # 管理者メールアドレス ADMIN_MAIL = '***'; def sendmail(set) if set.key?(:from_name) set[:from] = NKF.nkf('-jM',set[:from_name]) <<'<'<< set[:from] <<'>' end if set.key?(:to_name) set[:to] = NKF.nkf('-jM',set[:to_name]) <<'<'<< set[:to] <<'>' end IO.popen(SENDMAIL<<' -t','w') do |p| p.print "From: #{set[:from]}\n" p.print "To: #{set[:to]}\n" p.print "Subject: #{NKF.nkf('-jM',set[:sub])}\n" p.print "Content-Type: text/plain; charset=\"iso-2022-jp\"\n" p.print "Content-Transfer-Encoding: 7bit\n" p.print "MIME-Version: 1.0\n\n" p.print "#{NKF.nkf('-j',set[:body])}" end end # 送信サンプル set = { from: ADMIN_MAIL, from_name: '送信者', to: ADMIN_MAIL, to_name: '受信者', sub: '件名', body: 'メール本文' } sendmail(set)

動作チェック用のコードも載せておきます。入力エラーの時、エラー用のURLへ飛ばし、送信後は完了用のURLへ飛ばしています。Rubyでは、標準ライブラリのresolvでメールアドレスのドメインチェックを行えます。

# ドメインチェック用 require 'resolv' # フォームから送信があった時 if ENV['REQUEST_METHOD']=='POST' send = $_POST.fetch('from','') name = $_POST.fetch('name','').force_encoding('utf-8') sub = $_POST.fetch('sub','').force_encoding('utf-8') body = $_POST.fetch('body','').force_encoding('utf-8') # メールドメインの確認 domain = false if send =~ /@([^@]+)z/ res = Resolv::DNS.open r = res.getresources($1, Resolv::DNS::Resource::IN::MX) if 0 < r.size domain = true else r = res.getresources($1, Resolv::DNS::Resource::IN::A) if 0 < r.size domain = true end end end # お名前、メールアドレスが空欄、ドメインが存在しない場合エラー if name=='' || send=='' || domain==false print "Status: 301 Moved Permanently\n" print 'Location: '<<ENV['SCRIPT_NAME']<<"?result=error\n\n" exit end body = <<EOT お名前:#{name} メールアドレス:#{send} お問い合わせ内容: #{body} EOT # 管理者へメール body1 = <<EOT 下記の問い合わせがありました。 #{body} EOT s = { to: ADMIN_MAIL, to_name: '管理者', from: send, from_name: name, sub: sub, body: body1 } sendmail(s) # 送信者へメール body2 = <<EOT 下記の送信を行いました。 #{body} EOT s = { to: send, to_name: name, from: ADMIN_MAIL, from_name: '自動返信', sub: '[送信控え]' << sub, body: body2 } sendmail(s) print "Status: 301 Moved Permanently\n" print 'Location: '<<ENV['SCRIPT_NAME']<<"?result=success\n\n" exit end

Rubyでは、ヒアドキュメントによりHTMLタグをプログラムソース内に記述出来ます。

print "Content-Type: text/html; charset=utf-8\n\n" print <<HTML <html> <head> <meta charset="utf-8"> <title>[Ruby]お問い合わせフォーム</title> <style> table { margin: 50px auto; width: 500px; } td { padding: 5px 0; } input,select,textarea { padding: 5px; width: 100%; } textarea { height: 100px; } .required { color: red; } #caution { margin-top: 50px; text-align: center; color: #a00; } #complete { margin-top: 50px; text-align: center; color: #060; } </style> </head> <body> HTML if $_GET.fetch('result','')=='success' print <<HTML <div id="complete">送信を実行しました。ご返信まで今しばらくお待ちください。</div> </body> </html> HTML exit elsif $_GET.fetch('result','')=='error' print '<div id="caution">必須事項をご入力ください</div>' end print <<HTML <form method="post"> <table> <tr> <th>件名</th> <td> <select name="sub"> <option value="資料のご請求">資料のご請求</option> <option value="お申込み">お申込み</option> <option value="お問い合わせ">お問い合わせ</option> </select> </td> </tr> <tr> <th>お名前<span class="required">*</span></th> <td> <input type="text" name="name"> </td> </tr> <tr> <th>メールアドレス<span class="required">*</span></th> <td> <input type="text" name="from"> </td> </tr> <tr> <th>お問い合わせ内容</th> <td> <textarea name="body"></textarea> </td> </tr> <tr> <td colspan="2"><input type="submit" value="送信"></td> </tr> </form> </body> </html> HTML

Rubyで別サーバからメールを送信する方法

別サーバにあるメールサーバから送信したい場合、SMTPサーバに接続して送信する事になります。Rubyでは、メール送信ライブラリとしてnet/smtpを利用できます。

#!/usr/bin/ruby # coding: utf-8 require 'nkf' require 'net/smtp' # SMTPサーバ MAIL_HOST = '***' # 接続ユーザ MAIL_USER = '***' # パスワード MAIL_PASS = '***' # ポート番号 MAIL_PORT = 587 def sendmail(set) from = set[:from] if set.key?(:from_name) from = NKF.nkf('-jM',set[:from_name]) <<'<'<< set[:from] <<'>' end to = set[:to] if set.key?(:to_name) to = NKF.nkf('-jM',set[:to_name]) <<'<'<< set[:to] <<'>' end Net::SMTP.start(MAIL_HOST, MAIL_PORT, MAIL_HOST, MAIL_USER, MAIL_PASS, :plain) do |p| p.enable_tls(OpenSSL::SSL::VERIFY_NONE) p.open_message_stream(set[:from], set[:to]) do |f| f.puts "From: #{from}" f.puts "To: #{to}" f.puts "Subject:#{NKF.nkf('-jM',set[:sub])}" f.puts 'Content-Type: text/plain; charset="iso-2022-jp"' f.puts "Content-Transfer-Encoding: 7bit" f.puts "MIME-Version: 1.0\n\n" f.puts "#{NKF.nkf('-j',set[:body])}".force_encoding(Encoding::ASCII_8BIT) end end end # 送信サンプル set = { from: MAIL_USER, from_name: '送信者', to: MAIL_USER, to_name: '受信者', sub: '件名', body: 'メール本文' } sendmail(set)