メルマガを発行していて部数が増えてくるとよくあるのが、宛先からの自動返信。
「勝手に送ってくんなボケ」とか
「Re:クソスパマーへ返信します。」
とかいろいろ。
あと最近多いのが、
「いつも、メルマガ、楽しみに拝見しています。
実は、今回、メルマガ発行者さんに伝えたいことがあってメールしました。
・
・
・
このシステムで毎月、収入を得ています。
何もできない私でできるのですから、こんな素晴らしいメルマガを
書かれる方なら、きっとできることでしょう。
一度、下記のホームページをご覧になって下さい。
→URL」
といった、稼げる系の情報商材を自動返信で売り込んでくるメール。
だいたい送信元はgooメールかGメールのどちらか。
もちろん私は同意を得ていないメールアドレスをメルマガに勝手に登録したりしませんから、ボケとかクソとかは完全に向こう側のおかどちがいなのですが、さすがに毎回ボケとかクソとか言われるのは腹が立つ。
過去記事(http://www.igreks.jp/dev/2009/06/pop.html)で書いたPOPアクセスを用いてメルマガなどのエラーアドレスを自動で処理できる。
しかし、このやり方だけだと自動返信メールが処理できない。
なぜなら故意に設定された自動返信メールは、本文中にFROMとかTOとかSMTPサーバの返すメッセージが書いてないから。
つまり、フツーのメールを装って送信されてくる。
なので、前回のスクリプトを改良して自動返信メールにも対応させてみる。
[動作条件]
・perl5以上(確認した環境はは5.10)かつMail::POP3Clientモジュールがインストールされていること。
・POPアクセスにSSLを用いる場合(Gmailなど)は、さらにIO::Socket::SSLモジュール(要コンパイラ)が必要。
・あらかじめエラーメール受信専用のアドレスを作っておいて、メール送信する時にエンペロープFROMをそのアドレスに指定しておく。
・CRONなどで以下のスクリプトを実行する。
-------------------------------------------------------------------
#/usr/bin/perl -w
use strict;
use Mail::POP3Client;
my $log = "POPサーバに接続中・・・\n";
#コンストラクタ
my $pop = new Mail::POP3Client(
USER => 'pop_user', #popサーバのユーザ名
PASSWORD => 'pop_pwd', #同パスワード
HOST => 'pop.gmail.com', #popサーバ名
AUTH_MODE => 'BEST', #認証モード(たいていはBESTでOK)
DEBUG => 0, #デバッグ有無(正の整数を指定すると、プロンプトにサーバとのやりとりが表示される)
TIMEOUT => 10, #接続タイムアウト秒(デフォルトは60)
USESSL => 'true' #SSLを使わない場合は0(Gmailは使う)
);
if($pop->Count < 0){ #接続に失敗すると-1が返るらしい
$log .= "POPサーバに接続できませんでした";
}
else{
$log .= "ID[$id]のエラーメールアドレスを調査中・・・\n";
if($pop->Count != 0){
my $cnt = $pop->Count;
my @err = ();
my $suc = 0;
my %diag = (); ### エラーの原因格納用ハッシュ(任意)
my @next_ck = ();
$log .= " $cnt件のエラーメールアドレスを処理中・・・\n";
for(my $i=1; $i<=$cnt; $i++){
my $pars_ok = 0; #### パース成功フラグ
foreach($pop->Body($i)){
###本文(SMTPサーバが返すメッセージ)からエラーになった宛先をパース
if(
$_ =~ /^To:.*?\?iso-2022-jp\?B\?.+?\?=.*?<([\d\w-.+]+\@[\d\w-]+(\.[\d\w-]+)+)>/i ||
$_ =~ /^Delivered-To:.*?([\d\w-.+]+\@[\d\w-]+(\.[\d\w-]+)+)/i ||
$_ =~ /^X-Yahoo-Forwarded:.*?from.*?([\d\w-.+]+\@[\d\w-]+(\.[\d\w-]+)+).*?to/i
){
$pars_ok = 1;
push(@err,$1);
$suc++;
$pop->Delete($i);
####### Diagnosis エラーの原因チェック
if($_ =~ /5\.4\.4|Host.*?not found/i){
$diag{'Host_not_exists'}++; #ホストまたはドメインが存在しない
}
elsif($_ =~ /550|553|554|5\.0\.0|5\.1\.1|5\.7\.1/){
$diag{'Account_not_exists'}++; #受信先又は転送先のアカウントが存在しない
}
elsif($_ =~ /421|450|4\.2\.1|User disk quota/i){
$diag{'Mailbox_unavailable'}++; #受信先又は転送先のメールボックスが一時的に利用不可
}
elsif($_ =~ /451|452/){
$diag{'Server_error'}++; #配信時サーバエラー
}
elsif($_ =~ /432|454|534|535|538/){
$diag{'Authen_error'}++; #認証エラー
}
else{
$diag{'Other'}++; #その他
}
last;
}
}#foreach
###### パースできなかったエラーメールは次のチェックへ
push(@next_ck,$i) if !$pars_ok;
}#for
if(@next_ck != 0){
for(my $i=0; $i<@next_ck; $i++){
####### 今度はヘッダをチェック
foreach($pop->Head($next_ck[$i])){
if(
###### 自動返信元をパース
$_ =~ /^From:.*?([\d\w-.+]+\@[\d\w-]+(\.[\d\w-]+)+)/i ||
$_ =~ /^From:.*?\?iso-2022-jp\?B\?.+?\?=.*?<([\d\w-.+]+\@[\d\w-]+(\.[\d\w-]+)+)>/i
){
### パースされたアドレスがデータベースにあるかチェック
&db::query("SELECT email FROM usertable WHERE email='$1'");
my $exists = $db::sth->fetchrow_array();
if($exists){
### あれば削除対象に
push(@err,$1);
}
$suc++;
##### メール削除フラグ
$pop->Delete($next_ck[$i]);
$diag{'Auto_return'}++; #自動返信が設定されている
last;
}
}#foreach
}#for
}
if(@err){
####エラーアドレスをDBから削除する処理など
foreach(@err){
&db::query("DELETE FROM usertable WHERE email='$_'");
}
$log .= "$suc件のエラーメールアドレスをデータベースから削除しました\n";
}
###パースに失敗することもあるでしょう。
if(($cnt- $suc) > 0){
$log .= "※".($cnt- $suc)."件のエラーメールアドレスを削除できませんでした\n";
}
}
else{
$log .= "エラーメールアドレスはありませんでした\n";
}
}
#接続終了(このときメールがサーバから削除される)
$pop->Close;
print $log;
------------------------------------------------------------------------
あー疲れた。
「勝手に送ってくんなボケ」とか
「Re:クソスパマーへ返信します。」
とかいろいろ。
あと最近多いのが、
「いつも、メルマガ、楽しみに拝見しています。
実は、今回、メルマガ発行者さんに伝えたいことがあってメールしました。
・
・
・
このシステムで毎月、収入を得ています。
何もできない私でできるのですから、こんな素晴らしいメルマガを
書かれる方なら、きっとできることでしょう。
一度、下記のホームページをご覧になって下さい。
→URL」
といった、稼げる系の情報商材を自動返信で売り込んでくるメール。
だいたい送信元はgooメールかGメールのどちらか。
もちろん私は同意を得ていないメールアドレスをメルマガに勝手に登録したりしませんから、ボケとかクソとかは完全に向こう側のおかどちがいなのですが、さすがに毎回ボケとかクソとか言われるのは腹が立つ。
過去記事(http://www.igreks.jp/dev/2009/06/pop.html)で書いたPOPアクセスを用いてメルマガなどのエラーアドレスを自動で処理できる。
しかし、このやり方だけだと自動返信メールが処理できない。
なぜなら故意に設定された自動返信メールは、本文中にFROMとかTOとかSMTPサーバの返すメッセージが書いてないから。
つまり、フツーのメールを装って送信されてくる。
なので、前回のスクリプトを改良して自動返信メールにも対応させてみる。
[動作条件]
・perl5以上(確認した環境はは5.10)かつMail::POP3Clientモジュールがインストールされていること。
・POPアクセスにSSLを用いる場合(Gmailなど)は、さらにIO::Socket::SSLモジュール(要コンパイラ)が必要。
・あらかじめエラーメール受信専用のアドレスを作っておいて、メール送信する時にエンペロープFROMをそのアドレスに指定しておく。
・CRONなどで以下のスクリプトを実行する。
-------------------------------------------------------------------
#/usr/bin/perl -w
use strict;
use Mail::POP3Client;
my $log = "POPサーバに接続中・・・\n";
#コンストラクタ
my $pop = new Mail::POP3Client(
USER => 'pop_user', #popサーバのユーザ名
PASSWORD => 'pop_pwd', #同パスワード
HOST => 'pop.gmail.com', #popサーバ名
AUTH_MODE => 'BEST', #認証モード(たいていはBESTでOK)
DEBUG => 0, #デバッグ有無(正の整数を指定すると、プロンプトにサーバとのやりとりが表示される)
TIMEOUT => 10, #接続タイムアウト秒(デフォルトは60)
USESSL => 'true' #SSLを使わない場合は0(Gmailは使う)
);
if($pop->Count < 0){ #接続に失敗すると-1が返るらしい
$log .= "POPサーバに接続できませんでした";
}
else{
$log .= "ID[$id]のエラーメールアドレスを調査中・・・\n";
if($pop->Count != 0){
my $cnt = $pop->Count;
my @err = ();
my $suc = 0;
my %diag = (); ### エラーの原因格納用ハッシュ(任意)
my @next_ck = ();
$log .= " $cnt件のエラーメールアドレスを処理中・・・\n";
for(my $i=1; $i<=$cnt; $i++){
my $pars_ok = 0; #### パース成功フラグ
foreach($pop->Body($i)){
###本文(SMTPサーバが返すメッセージ)からエラーになった宛先をパース
if(
$_ =~ /^To:.*?\?iso-2022-jp\?B\?.+?\?=.*?<([\d\w-.+]+\@[\d\w-]+(\.[\d\w-]+)+)>/i ||
$_ =~ /^Delivered-To:.*?([\d\w-.+]+\@[\d\w-]+(\.[\d\w-]+)+)/i ||
$_ =~ /^X-Yahoo-Forwarded:.*?from.*?([\d\w-.+]+\@[\d\w-]+(\.[\d\w-]+)+).*?to/i
){
$pars_ok = 1;
push(@err,$1);
$suc++;
$pop->Delete($i);
####### Diagnosis エラーの原因チェック
if($_ =~ /5\.4\.4|Host.*?not found/i){
$diag{'Host_not_exists'}++; #ホストまたはドメインが存在しない
}
elsif($_ =~ /550|553|554|5\.0\.0|5\.1\.1|5\.7\.1/){
$diag{'Account_not_exists'}++; #受信先又は転送先のアカウントが存在しない
}
elsif($_ =~ /421|450|4\.2\.1|User disk quota/i){
$diag{'Mailbox_unavailable'}++; #受信先又は転送先のメールボックスが一時的に利用不可
}
elsif($_ =~ /451|452/){
$diag{'Server_error'}++; #配信時サーバエラー
}
elsif($_ =~ /432|454|534|535|538/){
$diag{'Authen_error'}++; #認証エラー
}
else{
$diag{'Other'}++; #その他
}
last;
}
}#foreach
###### パースできなかったエラーメールは次のチェックへ
push(@next_ck,$i) if !$pars_ok;
}#for
if(@next_ck != 0){
for(my $i=0; $i<@next_ck; $i++){
####### 今度はヘッダをチェック
foreach($pop->Head($next_ck[$i])){
if(
###### 自動返信元をパース
$_ =~ /^From:.*?([\d\w-.+]+\@[\d\w-]+(\.[\d\w-]+)+)/i ||
$_ =~ /^From:.*?\?iso-2022-jp\?B\?.+?\?=.*?<([\d\w-.+]+\@[\d\w-]+(\.[\d\w-]+)+)>/i
){
### パースされたアドレスがデータベースにあるかチェック
&db::query("SELECT email FROM usertable WHERE email='$1'");
my $exists = $db::sth->fetchrow_array();
if($exists){
### あれば削除対象に
push(@err,$1);
}
$suc++;
##### メール削除フラグ
$pop->Delete($next_ck[$i]);
$diag{'Auto_return'}++; #自動返信が設定されている
last;
}
}#foreach
}#for
}
if(@err){
####エラーアドレスをDBから削除する処理など
foreach(@err){
&db::query("DELETE FROM usertable WHERE email='$_'");
}
$log .= "$suc件のエラーメールアドレスをデータベースから削除しました\n";
}
###パースに失敗することもあるでしょう。
if(($cnt- $suc) > 0){
$log .= "※".($cnt- $suc)."件のエラーメールアドレスを削除できませんでした\n";
}
}
else{
$log .= "エラーメールアドレスはありませんでした\n";
}
}
#接続終了(このときメールがサーバから削除される)
$pop->Close;
print $log;
------------------------------------------------------------------------
あー疲れた。

コメントする