携帯向けの送信エラーメールを解析する

携帯へメール送信した際に、受信拒否やアドレス不明でエラーメールが返信されてくる場合があるが、この解析を行いたい。

ソフトバンク等、他のキャリアもエラーは発生するのだろうが、手元に保存していたエラーメールを見直してみるとドコモとau (EZWeb)分しかなかった。とりあえずは、この2種のみに対応する。また、エラーにも種々あるだろうがアドレス不明の場合の「User Unknown」のみを対象とする。

まず、エラーメールは「Content-Type: multipart/report; report-type=delivery-status;」形式で送信されてくる。3パートになっていて以下の形式(「Content-Description (Content-Type)」):

  1. Notification (text/plain)
  2. Delivery report (message/delivery-status)
    ※EZWebの場合は「Delivery error report」となる場合もあるようだ。
  3. Undelivered Message (message/rfc822)

1番目の「Notification」と2番目の「Delivery report」はどちらもエラー状況を示す内容的には同じだが表現が異なり、前者が人間可読用、後者が機械向けヘッダ付き表現用という感じ(3番目の「Undelivered Message」は実際に配信されなかったメールメッセージが入ってくる)。

エラーについては、ドコモの場合がちょっと厄介でわかりにくい。

1つめのパートの「Notification」で、宛先が「AAA@docomo.ne.jp, BBB@docomo.ne.jp, CCC@docomo.ne.jp, XXX@docomo.ne.jp, YYY@docomo.ne.jp」と5つある場合に、終わりの2つのXXX, YYYがアドレス不明(@docomo.ne.jpを省略)だと、エラー該当部の記述は次のような形になる。

<AAA@docomo.ne.jp>: host mfsmax.docomo.ne.jp[NNN.NNN.NNN.NNN] said:
    550 Unknown user XXX@docomo.ne.jp
    YYY@docomo.ne.jp (in reply to end of DATA command)

<BBB@docomo.ne.jp>: host mfsmax.docomo.ne.jp[NNN.NNN.NNN.NNN] said:
    550 Unknown user XXX@docomo.ne.jp
    YYY@docomo.ne.jp (in reply to end of DATA command)

<CCC@docomo.ne.jp>: host mfsmax.docomo.ne.jp[NNN.NNN.NNN.NNN] said:
    550 Unknown user XXX@docomo.ne.jp
    YYY@docomo.ne.jp (in reply to end of DATA command)

エラーなのはXXX, YYYなのだが、メッセージ行頭はアドレスが存在しているAAA, BBB, CCCがそれぞれ並び、さらに送信できたユーザ分だけ同じエラーメッセージが繰り返されてしまう。

エラーメールの解析システムとして「bounceHammer(バウンスハンマー)」というのを見つけて少し試してみたのだが、このツールだとエラーの宛先としては上記の不明アドレスのXXX, YYYでなく、配信されたAAA, BBB, CCC側を対象アドレスとして検出してしまうようだった。

このため、XXX, YYYを抜き出すためには、行頭のアドレスは無視してコロン「:」以降のメッセージ中「Unknown User … (」の間のアドレスを抜き出し、各通知での重複を除かなければならない。

EZWebだとXXX@ezweb.ne.jpのエラーで

<XXX@ezweb.ne.jp>: 550 user unknown (in reply to RCPT TO command)

のようになるパターンと

<XXX@ezweb.ne.jp>: host lsean.ezweb.ne.jp[NNN.NNN.NNN.NNN]
    said: 550 <XXX@ezweb.ne.jp>: User unknown (in reply to
    RCPT TO command)

のようになるパターンがある。おそらく後者が新しいもので、ドコモの形式ともだいたい一致している(表記が統一されたのかもしれない)。EZWebだと不明アドレスのみが通知されてくるのでわかりやすい。

2つめのパートの「Delivery report」は、ドコモだと

Content-Type: message/delivery-status;
 charset=UTF-8
Content-Transfer-Encoding: 7bit
Content-Description: Delivery report

Reporting-MTA: dns; mechsys.tec.u-ryukyu.ac.jp
X-Postfix-Queue-ID: 0000000
X-Postfix-Sender: rfc822; PPP@mechsys.tec.u-ryukyu.ac.jp
Arrival-Date: WWW, 00 MMM YYYY HH:MM:SS +0900 (JST)

Final-Recipient: rfc822; AAA@docomo.ne.jp
Action: failed
Status: 5.0.0
Diagnostic-Code: X-Postfix; host mfsmax.docomo.ne.jp[NNN.NNN.NNN.NNN] said: 550
    Unknown user XXX@docomo.ne.jp
    YYY@docomo.ne.jp (in reply to end of DATA command)

Final-Recipient: rfc822; BBB@docomo.ne.jp
Action: failed
Status: 5.0.0
Diagnostic-Code: X-Postfix; host mfsmax.docomo.ne.jp[NNN.NNN.NNN.NNN] said: 550
    Unknown user XXX@docomo.ne.jp
    YYY@docomo.ne.jp (in reply to end of DATA command)

Final-Recipient: rfc822; CCC@docomo.ne.jp
Action: failed
Status: 5.0.0
Diagnostic-Code: X-Postfix; host mfsmax.docomo.ne.jp[NNN.NNN.NNN.NNN] said: 550
    Unknown user XXX@docomo.ne.jp
    YYY@docomo.ne.jp (in reply to end of DATA command)

となり、EZWebだと

Content-Type: message/delivery-status;
 charset=UTF-8
Content-Transfer-Encoding: 7bit
Content-Description: Delivery error report

Reporting-MTA: dns; lsean.ezweb.ne.jp
Arrival-Date: WWW, 00 MMM YYYY HH:MM:SS +0900 (JST)

Final-Recipient: rfc822; XXX@ezweb.ne.jp
Action: failed
Status: 5.0.0

または、

Content-Type: message/delivery-status;
 charset=UTF-8
Content-Transfer-Encoding: 7bit
Content-Description: Delivery report

Reporting-MTA: dns; mechsys.tec.u-ryukyu.ac.jp
X-Postfix-Queue-ID: 0000000
X-Postfix-Sender: rfc822; PPP@mechsys.tec.u-ryukyu.ac.jp
Arrival-Date: WWW, 00 MMM YYYY HH:MM:SS +0900 (JST)

Final-Recipient: rfc822; XXX@ezweb.ne.jp
Action: failed
Status: 5.0.0
Diagnostic-Code: X-Postfix; host lsean.ezweb.ne.jp[NNN.NNN.NNN.NNN] said: 550
    <XXX@ezweb.ne.jp>: User unknown (in reply to RCPT TO
    command)

となる(おそらく後者が新しい現在の形式)。「Diagnostic-Code」の中に、「Notification」にあったメッセージが入っている形になっている。

「Delivery report」の場合のヘッダ解析等が簡単に扱えればそちらを選択したほうがよかったかもしれないがちょっと面倒そうで、同内容を含んでいて行を連結するだけですぐに対応できそうな「Notification」を使うことにした。

参考

ドットインストール用のGreasemonkeyスクリプト (2)

(過去の記事:←「ドットインストール用のGreasemonkeyスクリプト」)

作成したグリモンスクリプトを、「もしかしたらChromeでも動くかも?」と思って、Chromeの拡張を探していたら「NinjaKit」というのが見つかって、こちらで試していると自前で追加しているチェックボックスは表示されるものの、unsafeWindowなどが動作しない感じ。

動作は無理かと思っていたら、別で「Tampermonkey」という拡張が見つかってこちらだと動作した。
20140623121544

ただし、動画の自動再生がうまくいく場合といかない場合があり、どうもブラウザ立ち上げ時のloadイベントでは再生できるが、ページ再読み込み時のloadイベントでは動作しない感じ。このため、loadイベントへの割り当てを単にfunction(){}にするのでなく、setTimeout()で指定するようにしてみた。タイムアウトは500ms程度でも大丈夫そう。

@@ -31,3 +31,3 @@
         if ($('#auto-play').prop('checked')) {
-           addEventListener('load', function(){unsafeWindow.HMHM.movie.vimeo.player.playVideo();});
+           addEventListener('load', function(){setTimeout(function(){unsafeWindow.HMHM.movie.vimeo.player.playVideo();}, 500);});
         }

別で、GreaseKitというのも見つかったが、これはさらにNinjaKitよりも古いものだったようだ。

スクリプト

// ==UserScript==
// @name        DotInstallLessonAutoPlayAndComplete
// @namespace   http://mechsys.tec.u-ryukyu.ac.jp/~oshiro/
// @include     http://dotinstall.com/lessons/*/*
// @version     ver.0.2
// @grant       GM_getValue
// @grant       GM_setValue
// @grant       unsafeWindow
// @require http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js

// @require http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/jquery-ui.min.js

// ==/UserScript==

(function(){
    // 動作切り替えチェックボックスの追加

    $("#lesson-complete-button").parent().append('<div>')
       .append('<input id="auto-play" name="autoplay" type="checkbox">自動再生')
       .append('<input id="next-complete" name="nextcomplete" type="checkbox">自動完了チェック')
       .append('<input id="return-list" name="returnlist" type="checkbox">全完了時に一覧へ');
    
    // 動作設定の復帰と切り替え時の設定登録

    $('#auto-play').prop("checked", GM_getValue('DotInstallAutoPlay', true));
    $('#next-complete').prop("checked", GM_getValue('DotInstallNextComplete', true));
    $('#return-list').prop("checked", GM_getValue('DotInstallReturnList', true));

    $('#auto-play').change(function(){GM_setValue('DotInstallAutoPlay', $('#auto-play').prop("checked"));});
    $('#next-complete').change(function(){GM_setValue('DotInstallNextComplete', $('#next-complete').prop("checked"));});
    $('#return-list').change(function(){GM_setValue('DotInstallReturnList', $('#return-list').prop("checked"));});

    // 動画の自動再生
    if ($('#completeButtonLabel')[0].innerHTML.match(/^\s*完了\s*$/)) { // 未完了(「完了」ラベルがある)なら
        if ($('#auto-play').prop('checked')) {
            addEventListener('load', function(){setTimeout(function(){unsafeWindow.HMHM.movie.vimeo.player.playVideo();}, 500);});
        }       
    }
    // 「次へ」ボタンの動作

    $('#lesson-complete-button').next().click(function() {
       var href = $(this).attr('href');
        if ($('#return-list').prop('checked') && $(this).hasClass('disabled')) {href = window.location.href.replace(/[^/]+$/, '');} // 最後のリンクではレッスン一覧へ

       if ($('#completeButtonLabel')[0].innerHTML.match(/^\s*完了\s*$/) && $('#next-complete').prop('checked')) {
          unsafeWindow.$('#lesson-complete-button').click();
          //alert('完了しました!');
      }
      if (!$('#lesson-complete-button').next().hasClass('disabled') || $('#return-list').prop('checked')) {
          setTimeout(function(){window.location=href;}, 800); // レッスンの「完了」操作が終わるくらいまで待って移動
      }
      return false;
    });
})();

ChromeでScrollar Anywhere

Firefoxでのドラッグスクロールが便利だった(←「FirefoxでGrab and Drag」)ので、Chromeでも同じようなことができないかと拡張を探すと、次の「Scrollbar Anywhere」があった。

Scroll Anywhere

Firefoxの「Grab and Drag」と同じような感じの動作になるよう設定した(Scalingは下ドラッグで下スクロールになるよう負の値にしている)。

20140618193412

FirefoxでGrab and Drag

Firefoxでの便利な拡張があったので設定も含め掲載。

20140618190312

マウスクリックで掴んでそのままページをスクロールできる。デスクトップのマウス操作でも、タブレットでのウェブ閲覧のようなフリック動作が行ないやすい。

また、Firefox内でpdfを表示させた際にはその内容でもマウスでフリックできるようになり、閲覧に便利。

次のような設定にしてみた。左ボタンでフリックがしやすいような感じを意図している(赤枠が変更箇所):

20140618185422 20140618184534

20140618184549 20140618184554

20140618184600 20140618184604

Chromeでの話も↓

WordPress: プラグイン PHP Hilight String がなくなっている

このブログでのプログラム記述にはWordPressプラグインの「PHP Highligh String」を使っている(PHPとなっているが、各種言語に対応)。

(また、自前のMemoLinkプラグインの作成時にも参考にさせて頂いた:

ふとWordPressのプラグイン一覧を眺めていたら、このプラグインの箇所で正しい日本語の説明ともう一つ文字化けになっている説明と2つ表示されていたので、文字化け分のみ消そうと「削除」とやったら、(プラグイン名が同じせいか)両方とも削除されてしまった。

保存はしていなかったので、再度ネットで探そうとしたがこれが見つからない。

作者の方のページ(http://www.chameleonic.org/plugin/)もサイト自体は存在しているものの、プラグインページは404になっていて、またサイトトップもApacheの初期画面のままになっている。

仕方ないので、WebArchiveから入手…。

存在していたのは2012年5月までで、それ以降は404になっているらしい。

どうも2012年11月頃にアカウントの更新忘れでデータが消えていた模様。

更新がないとなると、今後のコード表示は別のプラグインを探したほうがいいのかな。

あと、改めて見ていると、このプラグイン名の表記が統一されていない。プラグインのファイルの内容自体では「PHP Highligh String」の表記となっていて、プラグインの説明ページのタイトルには「PHP Hilight String」、プラグイン一覧には「PHP HilightString」と。

関連リンク(概ね2008~2009年頃のもの)

このプラグインと同名のPHPの基本関数もあった: