[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

(DTPtechNote:1133) [ruby] fwd_important-mail.rb(簡易メール転送クライアント)



京ぽん(京セラAH-K3001V)が音声・Mailともに定額になりました。
特定の相手からのメールを24時間いつでもキャッチしたいと思って、
earth.rb 3.6.1(http://www.fjts.org/~m/Soft/Ruby/earth.rb/)
を導入してみましたが、ウチのプロバイダ(ASAHIネット)はちゃんと未読管理とかしてくれない。
サーバー上で動作する、わたしの希望に添うようなメールクライアントも探してみましたが、どれもいまひとつ。
んで、rubyで書いちゃいました。
アイデアをいただいたり、部分的にコードを書いていただいたりしたaiboさんに感謝します。

#!/usr/bin/ruby
=begin
fwd_important-mail.rb	0.1
簡易メール転送クライアント

環境;
ruby 1.8.2が動くこと。

使い方;
メールサーバーの設定を変数に入れてください
実行ユーザーのオーナーで、パーミッションを700にセットしてください
適宜サーバー上のcrontabで定期的に実行してください。

histry;
2005.05.17	ver.0.1
=end

#らいぶらりー
require "socket"
require 'net/pop'
require "net/smtp" # SMTPライブラリの読込
require "kconv" # kconvライブラリの読込


##======================================================変数と設定
popserver = '【ここにPOPサーバー名をいれる(例:pop.asahi-net.or.jp)】'##POPサーバー名(受信)
smtpserver = '【ここにSMTPサーバー名をいれる(例:mail.asahi-net.or.jp)】'##SMTPサーバー名(送信)
accunt = '【ここにアカウント名を入れる(例:ym3s-ickw)】'#アカウント
passwd = '【ここにパスワードを入れる(例:openthesesami)】'#パスワード

#from行にこれらのアドレスが含まれていれば、転送処理対象とする
targetaddress = '【ここに処理対象のメールアドレスを入れる。複数のアドレスは「|」で区切ること。正規表現つかえます。こんな感じ。(例;hoghoge@mac.com|ym3s-ickw@asahi-net.or.jp|@thinks-net.co.jp)】'
fromaddress = '【ここに転送元アドレスを入れる(例:ym3s-ickw@asahi-net.or.jp)】'#転送元アドレス
toaddress = '【ここに転送先アドレスを入れる(例;hogehoge@dk.pdx.ne.jp)】'#転送先アドレス

nobody = false#メール着信のおしらせだけならtrue。メッセージも転送するならfalse
attachments = false#添付ファイルを転送するかどうか? 転送するtrue, 転送しないfalse


#必要なファイル このプログラムと同じ階層に下記のファイルができます。
mypwd = Dir.pwd
mail_idlog = mypwd + "/mail_idcheck.txt"





##======================================================メソッド
#-------------------------------------------------------def error message
def my_error(errMess)
  puts "Error!\n" + errMess
  exit#プログラム終了
end


#-------------------------------------------------------def my_exist
#########ファイル読み書き用メソッド
#ファイルの存在確認
def my_exist(filepath)
	unless FileTest.exist?(filepath) then#もしなかったら
		system("touch " + filepath)#ファイル作るだす
	end
	if !(FileTest.readable_real?(filepath)) then#読み込み不可なら
		my_error("Don't Read This File.")
	elsif !(FileTest.writable_real?(filepath)) then#書き込み不可なら
		my_error("Don't Write This File.")
	end
end

#-------------------------------------------------------def fileread
#ファイル(filepath)を読み込んで、ハッシュを返す。値の初期値はfalse
def fileread(filepath)
	myhash = Hash.new
	File.open(filepath, 'r') { |io|
		while line = io.gets
			line.chomp!#改行を削除して
			myhash[line] = false#初期値はfalse
		end
	}
	return myhash
end

#-------------------------------------------------------def
#filepathにstrを新規書き込み
def filewrite(filepath, str) 
	File.open(filepath, 'w') { |file|
	file.puts str
}
end
#-------------------------------------------------------def
#フラグの立っているキーを文字列化
#ハッシュ(myhash)を渡されたら、tureの値を持つキーだけを集めて(falseを値にもつキーを削除して)、改行でひとかたまりの文字列にする
def hash2str(myhash)
	myhash.delete_if {|key, value| value == false}
	str = myhash.keys.join("\n")
	return str
end



#########ここからメール送信用メソッド
#-------------------------------------------------------メールテキスト作成メソッド
def make_mail_text(subject, from, to, multipart_header, body)
# メールのテキストの作成
mail_text = <<-EndOfMail
Subject: Fwd:#{subject}
To: #{to}
From: #{from}
Content-Type: text/plain; charset='iso-2022-jp'
Content-Transfer-Encoding: 7bit
MIME-Version: 1.0
#{multipart_header}
#{Kconv::tojis(body)}
EndOfMail
return(mail_text)
end

#-------------------------------------------------------メールの送信
def send_mail(smtpserver, src, from, to)
	timeout(20) do
		Net::SMTP.start( smtpserver, 25 ) do |session|
			session.send_mail( src, from, to )
		end
	end
end

#-------------------------------------------------------メールの全体からボディだけを返す
#実はここは使っていない^^参考程度に
def my_body(str)
	startpoint = str.index( "\r\n\r\n" ) + 4
	return str[ startpoint, str.size - startpoint ].to_s 
end

#こっちでやってます
module Net
	class POPMail
		def body
			self.all[self.header.size .. -1]
		end
	end
end




##======================================================メイン
my_exist(mail_idlog)
myhash = fileread(mail_idlog)

begin

Net::APOP.start(popserver, 110, accunt, passwd) {|pop|
if pop.mails.empty? then#もしメールボックスが空だったら
	puts "No Mail"
else 
	mail_count=pop.mails.size #メール総数
	puts "Receved Mail  +#{mail_count}\n"
	pop.each { |mmail| ##1通1通のメールの処理
		mail_id=mmail.unique_id #ユニークidのゲット
		if myhash.key?(mail_id) then#既読メールであった
			myhash[mail_id] = true#値をセット
		else #myhashにふくまれていなければ
			mail_header=mmail.header#ヘッダをget
			address_re = Regexp.new("From: (.*" + targetaddress + "[^\n]*)")#正規表現の生成
			if mail_header =~ address_re#targetaddressに含まれていれば
				mailfrom = $1
				puts mailfrom#だれからのメールかをコンソールに出力
				mail_header =~ /Subject: ([^\n]*)/
				mailsubject = $1#Subjectの取得
				
				#メール着信のみのお知らせか、メッセージも転送するか
				if nobody then#お知らせだけなら
					mail_body = "You got a Mail!\nFrom: " + mailfrom + "\nSubject: " + mailsubject
				else#以下ボディ処理
					mail_body = mmail.body#ボディ全体の取得
					
					#添付ファイルの処理(大きなデータである可能性もあるので、メソッドにしない)
					#ヘッダ中にmultipartがあれば取得しておく
					if (mail_header =~ /^(Content-Type: multipart.+boundary=\"([^\"]+)\")/) then
						multipart_header = $1 + "\n"#Content-Typeヘッダの取得
						boundary = '--' + $2#区切り文字の取得
					end
					if !(attachments) then#添付ファイルを転送しない設定なら
						multipart_header = "\n"#Content-Typeヘッダをなしに
						startpoint = mail_body.index("\r\n\r\n") + 4#最初の空行までのバイト数
						endpoint = mail_body.index(boundary, startpoint) -1#空行から区切り文字までのバイト数
						mail_body = mail_body[startpoint .. endpoint].to_s
					end
				end#if nobody
					
				# smtpでメールの送信と例外処理
				begin
					mail_src = make_mail_text(mailsubject, fromaddress, toaddress, multipart_header, mail_body) # メールソースの作成
					send_mail(smtpserver, mail_src, fromaddress, toaddress)
				rescue
					my_error("send_mail\n$!")
				end
				myhash[mail_id] = true#キーと値をセットして既読とする
			end
		end  #if myhash.key?(mail_id)
	} #end pop.each
	#既読状態のものを書き込み
	str = hash2str(myhash)
	filewrite(mail_idlog, str)
end # pop.mails.empty?
} #end Net::APOP
rescue 
	my_error($!)
end
puts "It succeeded."