福祉支援サービス コミル
コミルは障害をお持ちの方の生活をモノの工夫によって豊かにすることをお手伝いします。
コミルは障害をお持ちの方の生活をモノの工夫によって豊かにすることをお手伝いします。
コミルは障害をお持ちの方の生活をモノの工夫によって豊かにすることをお手伝いします。
コミルのサイト内では、「できマウス。」プロジェクトのメーリングリスト「できML。」が動いています。
このメーリングリストはプレーンテキストのみ配信されますが、参加者の皆さんから投稿されるメールは(マイクロソフト謹製諸メールソフトの影響もあり)HTMLメール、添付ファイル付きのメールが絶えません。また、積極的に画像を添付なさろうとしていた参加者の方もおられました。
そこで、「できML。」ではメールサーバに届いた投稿メールを以下の通り加工して、メーリングリストシステムfmlに渡しています。
この処理を行っているのが、mpmfilter (Multi Part Mail Filter) です。
mpmfilter のソースは以下から。
#!/usr/bin/env ruby # #= メールのプレーンテキスト化フィルター # # 標準入力から読み込んだメールを # プレーンテキストに変換して # 標準出力に出力する # #注意事項:: 環境変数 LANG を適切に設定しておくこと # #ver.0.1.0:: 2008/08/27 #ver.0.1.1:: 2008/08/28 複数の plain/text パートがある時の対応 #ver.0.1.2:: 2008/08/31 メールに挿入する報告,注意文を変更 text/rfcなどに対応 #ver.0.1.3:: 2008/09/01 注意文を変更 #ver.0.1.4:: 2009/01/05 送信メールのBody前に空行を挿入(X-Wrong-Linesへの対策) #ver.0.1.5:: 2009/01/12 w3mとの接続にOpen3を使うよう変更 #ver.0.1.6:: 2009/01/14 0.1.4の変更を廃棄 ヘッダにCRが付かないようTMail::encodedの使用を中止 #ver.0.2.0:: 2009/01/19 限定した拡張子の添付ファイルは保存、公開する機能を追加 # #copyright:: Hiroyuki Mabuchi @ Comil[http://www.comil.jp/] # Version = "0.2.0" require 'tmail' require 'kconv' require 'logger' require 'open3' require 'uri' # プレーンテキストとして許可する content-type AllowType = %w[text/plain text/rfc822 message/plain message/rfc822] # 保存を許可する添付ファイルの拡張子 AllowExt = %w[jpg jpeg pdf doc xls ppt sxw odt ods odp docx docm xlsx xlsm pptx pptm jtd] # 添付ファイルを保存するディレクトリ BaseDir = "/var/www/bar-ml/" # 保存した添付ファイルを公開するURI BaseUri = "http://www.mydomain.com/bar-ml/" # メールに挿入するプログラムバージョン表記 ProgVersionStr = " この投稿は #{File.basename($0,".rb")} ver. #{Version} で変換されました。\n\n" # メールに挿入する注意文 Notice = <<EOS ※ ご注意ください ※ 本メーリングリストではHTMLメールおよび添付ファイル付きのメールは 配信せず、該当部分は自動で削除されます。 EOS # ログ記録の設定 log = Logger.new("#{ENV['HOME']}/mpmfilter.log", 'weekly') log.level = Logger::DEBUG # w3m のパス W3m = `which w3m`.chomp if W3m.empty? log.error "Not exist w3m." raise end # メールに挿入する作業報告文を返す(削除した) def report_deleted(type) " #{type} パートを削除しました。\n" end # メールに挿入する作業報告文を返す(変換した) def report_converted(type) " #{type} パートをプレーンテキストに変換しました。\n" end # メールに挿入する作業報告文を返す(追加した) def report_added(type) " #{type} パートを本文に追加しました。\n" end # メールに挿入する作業報告文を返す(保存した) def report_saved(type, file) " #{type} パートを保存しました。\n #{file} よりご覧下さい。\n" end # ネストを潜りながら Multi Part Mail の Content-Type, filename と Body を抽出 # Content-Type, filename と Body のハッシュの配列を返す def parse_multipart(mail) res = [] idx = 1 mail.parts.each do |m| m.base64_decode if m.multipart? res += parse_multipart(m) else file = m.disposition_param('filename') if file.nil? file = "#{idx}.#{ext(m)}" else file = file.gsub(/\n\s*/, " ").toutf8 file = $1 if /^"(.*)"$/ =~ file end res << {:content_type => m.content_type, :filename => file, :body => m.body} end idx += 1 end res end # Content_Type と拡張子の対応 CTYPE_TO_EXT = { 'image/jpeg' => 'jpeg', 'image/gif' => 'gif', 'image/png' => 'png', 'image/tiff' => 'tiff', 'application/vnd.ms-excel' => 'xls', 'application/msword' => 'doc' } # 添付ファイルの拡張子を決める def ext( mail ) CTYPE_TO_EXT[mail.content_type] || 'txt' end # Mail Object を作成する # body , content_type 以外はコピー元をそのまま使用する # 新たに作った Mail Object を返す def make_mail(src_mail, body, comment) new_mail = TMail::Mail.new src_mail.each_header do |header, field| new_mail[header] = field.to_s end new_mail.set_content_type('text', 'plain', {'charset'=>'iso-2022-jp'}) # new_mail.body = Kconv.tojis(body) + "\n" + Kconv.tojis(comment) new_mail.body = body.tojis + "\n" + comment.tojis new_mail.write_back new_mail end # w3m に通して Plain Text に変換する # 環境変数 LANG を適切に設定しておくこと def html2plain(str) htmlbody = [] Open3.popen3("#{W3m} -T text/html -dump -O j") do |stdin, stdout, stderr| stdin.print str stdin.close htmlbody << stdout.read end htmlbody.join end # main begin # 変換元メール 標準入力から読み込み src_mail_lines = readlines # fromwhom があれば送出 if /^From / =~ src_mail_lines.first print src_mail_lines.shift end # 元メールのオブジェクト src_mail = TMail::Mail.parse(src_mail_lines.join) if /\s*#nn\s*(.*)/i =~ src_mail.subject no_notice = true src_mail.subject = $1 else no_notice = false end if src_mail.multipart? # MultiPartメール log.info("Multh part mail.") body = "" addcomment = "" partslist = parse_multipart(src_mail) partslist.each do |part| if AllowType.include?(part[:content_type]) body << part[:body] addcomment << report_added(part[:content_type]) log.info("Added #{part[:content_type]} part.") elsif part[:content_type] == "text/html" && body.empty? body = html2plain(part[:body]) addcomment << report_converted(part[:content_type]) log.info("Converted #{part[:content_type]} part.") addcomment << report_deleted(part[:content_type]) log.info("Deleted #{part[:content_type]} part.") else filename = part[:filename] if AllowExt.include?(File.extname(filename).downcase.sub(/^\./,"")) dir = "#{Time.now.to_i}#{Process.pid}" filepath = BaseDir + dir Dir::mkdir(filepath) unless File.directory?(filepath) File.chmod(0755, filepath) filepath = "#{filepath}/#{filename}" File.open(filepath, 'wb') do |f| f.write part[:body] end File.chmod(0644, filepath) fileuri = "#{BaseUri}#{dir}/#{URI.encode(filename)}" addcomment << report_saved(part[:content_type], fileuri) log.info("Saved #{part[:content_type]} part on #{filepath}.") else addcomment << report_deleted(part[:content_type]) log.info("Deleted #{part[:content_type]} part.") end end end addcomment << ProgVersionStr unless addcomment.empty? addcomment << Notice unless addcomment.empty? or no_notice new_mail = make_mail(src_mail, body, addcomment) else if src_mail.body =~ /^<.*doctype.*html/i # MultiPart でない HTML メール log.info("Not multi part but also HTML mail.") addcomment = report_converted("mail body") addcomment << ProgVersionStr addcomment << Notice unless no_notice new_mail = make_mail(src_mail, html2plain(src_mail.body), addcomment) else # Plain Text Mail # 元のメールをそのまま出力 log.info("Plain text mail, so send through.") print src_mail_lines.join exit end end log.debug("Source Mail --->\n#{src_mail_lines.join}") print new_mail log.debug("Created new Mail --->\n#{new_mail}") rescue => err log.error err raise err end
/home/foo 以下にメーリングリスト bar-ml を fml で作成したとすると、上記ソースを /home/foo/bin/mpmfilter.rb として保存し、/home/foo/fml/spool/bar-ml/include を以下の通りに変更します。
"|LANG=ja_JP.UTF-8 && exec /home/foo/bin/mpmfilter.rb |/home/foo/fml/fml.pl /home/foo/fml/spool/bar-ml "
HTMLメールをプレーンテキストメールに変換するのは w3m を使用しています。予め w3m をインストールしておいて下さい。
また、ソース中の添付ファイルの保存先 BaseDir、その公開URL BaseUri、注意喚起文 Notice などは適切に変更して下さい。
blog comments powered by Disqus