後日 FreeBSD, Perl の Net::SMTP::TLS ではまるというのを書いた。 そちらも参考にしてみて欲しい。
2009年3月に FreeBSD上でPerlのスクリプトを使ってプロバイダの認証あり587番ポートからメールを送信する,という話を書いた。
今回,似たようなことをしたので,それを記録に残しておこうと思う。やった作戦は何かというと,Gmail(Googleのmail)のSMTPとPerlのスクリプトを組み合わせて,googleのアカウントからメールを送る,という作戦。なんでこんな作戦をしたくなったかというと,同窓会関係のメールの一斉送信のため。個人的に高校の同期の同窓会のサイトを作っているのだが,そのメンバーに一斉にメールをしたいことがあるのだが,メールする先はPCだったり携帯だったりする。それまでは,GmailでBcc: フィールドにアドレスを100以上並べて送信したのだが,この間その方法で送信すると,携帯で受け取った人から「文字化けで全然あかん」というお叱りを多数受け取った。そのうちPCで受け取った友人からも文字化けを指摘された。いろいろ見てみると,携帯によってはBcc:フィールドを他の目的で使うことがあるみたい。また,Bcc:フィールドを長くするとトラブルを生じるみたい。また,文字コードをデフォルトに設定していると,変な文字があるといつものISO-2022-JPではない文字コードにされてしまうみたい。そのため,ひどい文字化けが起こったようである。
そこで,いろいろ作戦を考えてみた。まずは,Perlのスクリプトを使って,うちのプロバイダのSMTPからメールを送信するのは以前やったので,それを使うという作戦。しかし,これは送信元がうちのアドレスになり,私一人で使ってるアドレスではないので,ちょっと難がある。他にも,メールアドレスを20個ずつぐらいに分割して,数回に分けて送信する,とか,google groupを複数作って(確か収容できるアドレスに最大値があったと思う → 制限はないかも…)そこから送信させる,など。しかし,どれもいまいちだった。そこでいろいろ調べているうち,gmailもsmtpで送信できる,というのを思い出した。そこで,「gmail smtp」で検索してみると,ちゃんとgoogleのヘルプページがひっかかった。それによれば
「送信メール (SMTP) サーバー - TLS を使用する場合」は,
・サーバーが「smtp.gmail.com (認証の使用)」で,
・認証が必要で,
・「STARTTLS の使用: オン」(TLSを使えということらしい),
・ポートは「465 または 587」を使い,
・アカウント名は「Gmail のユーザー名(「@gmail.com」を含む)」で,
・メールアドレスは「Gmail のメールアドレス (username@gmail.com)」,
・パスワードは「Gmailのパスワード」,
を使えば使えるみたい。
これなら,以前の投稿で書いたNet::SMTP::TLSとJcode.pmを使えば簡単に実現できそう。と,いうことで挑戦してみた。前回との違いは「NoTLS => 'NO',」という行を削除したぐらい。後は,subjectや本文,アドレスリストを別ファイルで用意しておいて,読み込ませるようにしておいた。
以下に,ソースコードを載せておこう。ちなみにプロのPerl使いとは違って,ちょっとどんくさい感じであるが,その点はご容赦願いたい。ここでは,subjectは同じディレクトリのsubjectという名前のファイルにテキストでいれている。subjectは短い方がよく,1行に収めないといけない(1行しか読み込んでない)。アドレスリストは同じく同じディレクトリにmaillistというファイル名のテキストファイルで用意する。これは1行に1アドレスのみとしている。TABで区切って名前や敬称などをいれて差し込むことも可能である(途中の「# $line =~ s/MMMM0MMMM/$name/;」という行はそのためにある。また,本文は同じディレクトリにmessageという名前のテキストファイルを用意しておく。
このスクリプトでは,短時間に大量に送信してスパム発信者と思われても困るので,メール送信とメール送信の間に7~17秒の間を置いている。この時間間隔でいいのか,あるいは長すぎるのか,は不明だが,一応100個程度のメールは送信はできた。もうちょっと短くてもいいかなぁ?という印象だが…
また,「GetTimeStr」,「GetDateStr」,「ZeroPadding」というサブルーチンはそれぞれ,時刻文字列,日付文字列,一桁の数字の前にゼロを加える,というルーチンである。
#! /usr/local/bin/perl # use Jcode; use Net::SMTP::TLS; # $min_wait_time = 7; # seconds $wait_time_width = 10; # seconds # my $mailhost = 'smtp.gmail.com'; my $mailport = 587; my $mail_username = 'xxxyyy@gmail.com'; my $mail_password = 'passwordpassword'; my $from_mail = 'xxxyyy@gmail.com'; # # # subject open(SUBJ, "./subject"); $subject=<SUBJ>; $subject=~ s/\s*$//; # remove spaces, cr and lf at the end close(SUBJ); $subject = jcode($subject)->jis; # # # get address list open(LIST, "./maillist"); $count=0; while(<LIST>) { $to_mail=$_; $to_mail =~ s/\s*$//; # remove spaces, cr and lf at the end if ($to_mail !~ /^#/) { $count++; $stop_time = $min_wait_time + int(rand($wait_time_width)); print '今から'.$stop_time.'秒待って xxxyyy@gmail.com からの送信を開始します。('.&GetTimeStr.")\n"; sleep($stop_time); print 'No.'.$count.": '".$to_mail."'宛の送信を開始しました。(".&GetTimeStr.")\n"; # # # get message $message= ''; open(MES, "./message"); my $line; while(<MES>) { $line=$_; # $line =~ s/MMMM0MMMM/$name/; # $line =~ s/MMMM1MMMM/$title/; $message=$message.$line; } close(MES); #------------------ $message = jcode($message)->jis; my $header; $header = "From: " . jcode("$from_mail")->mime_encode . "\n"; $header .= "To: " . jcode("$to_mail")->mime_encode . "\n"; $header .= "Subject: " . jcode($subject)->mime_encode . "\n"; $header .= "MIME-Version: 1.0\n"; $header .= "Content-type: text/plain; charset=ISO-2022-JP\n"; $header .= "Content-Transfer-Encoding: 7bit\n\n"; my $smtp = new Net::SMTP::TLS( $mailhost, # NoTLS => 'NO', Port => $mailport, User => $mail_username, Password => $mail_password ); $smtp->mail($from_mail); $smtp->to($to_mail); $smtp->data(); $smtp->datasend($header); $smtp->datasend($message); $smtp->dataend(); $smtp->quit; print 'No.'.$count.": '".$to_mail."'宛への送信が終了しました。(".&GetTimeStr.")\n"; print '---------------------------------------'."\n"; } # if } # while close(LIST); print '====================================================='."\n"; print 'xxxyyy@gmail.com から '.$count.' 名宛にメールを送信しました。'."\n"; print &GetDateStr.' '.&GetTimeStr."\n\n"; exit; #========================================== # # get time-string 時刻 # sub GetTimeStr { my(@GTS_date_array) = @_; if ($GTS_date_array[1] eq '') { @GTS_date_array = localtime(time); } my($dum); $dum=&ZeroPadding($GTS_date_array[2]).":".&ZeroPadding($GTS_date_array[1]) .":".&ZeroPadding($GTS_date_array[0]); return $dum; } # # get date-string 日付 # sub GetDateStr { my(@GTS_date_array) = @_; if ($GTS_date_array[1] eq '') { @GTS_date_array = localtime(time); } my($dum); $dum=($GTS_date_array[5]+1900)."/".&ZeroPadding($GTS_date_array[4]+1) ."/".&ZeroPadding($GTS_date_array[3]); return $dum; } # # zero padding ゼロで埋める(2文字の時だけ) # sub ZeroPadding { my($dum)=sprintf("%d",@_); $dum="00".$dum; $dum=substr($dum,(length($dum)-2)); return $dum; }上記のスクリプトを使う場合,maillistはテスト用を含めて複数用意しておいて,適宜maillistにコピーして使うと便利である。また,subjectやmessageは,subject.20100701のようにコピーしておくと,何を送ったかがわかってよいかもしれない。
このスクリプトを使って送信すると,gmailのアカウントの送信メールにずらっと送信した履歴が残る。あまりいっぱい残ってもいまいちなので,一斉にうまく消す方法を今模索しているところである。
(追記) script内で「<」と「>」をそのまま入力したら,htmlのタグと認識されてしまっていた。訂正しておいた。(2010/7/29)
0 件のコメント:
コメントを投稿