Waftで304 Not Modifiedを出力するコード

最近いろいろなプログラムで使い回している、Waftで304 Not Modifiedを出力するためのコード。本体に組み込もうかなぁ。

sub Waft::not_modified_since {
    my ($self, $last_modified_time) = @_;

    return if not $last_modified_time;
    return if not eval { require HTTP::Date };

    my $modified_time = HTTP::Date::str2time($ENV{HTTP_IF_MODIFIED_SINCE});

    if ( $modified_time and $modified_time == $last_modified_time ) {
        $self->add_response_header('Status: 304 Not Modified');
        $self->output;

        return 1;
    }

    my $last_modified_string = HTTP::Date::time2str($last_modified_time);
    $self->add_response_header("Last-Modified: $last_modified_string");

    return;
}

使い方は以下のとおり。directメソッド等の中で呼び出して、戻り値が真なら処理を終了させます。引数にコンテンツの更新日時をUNIX time(time関数で得られる形式)で指定してください。

sub __default__direct {
    my ($self) = @_;

    my $last_modified_time = ~; # データベース等から更新日時を取ってくる

    return if $self->not_modified_since($last_modified_time);

    return 'TEMPLATE';
}

.mailfilterでケータイへの転送メールを一部制限(さくらのレンタルサーバを使用)

NTTドコモの「メール使いホーダイ」を契約したので、メールだけはパケット代を気にせずケータイで送受信できるようになりました。PCで使っているメールもケータイに転送設定しておくと便利♪ではありますが、メールアドレスをWebにさらしているために迷惑メールがハンパない訳で、これが全部ケータイに転送されるととっても困ります。
そこでちょっと工夫が必要になりました。

メールサーバ内でSpamAssassinが動いてくれているので、これを使ってケータイへの転送を振り分けてみます。SpamAssassinが迷惑メールの程度をX-Spam-Levelで示してくれる(「*」が多いほど迷惑メールである可能性が高い)ので、まずその程度を決めてみました。
PCのThunderbirdで受け取っているこれまでのメールを「メッセージの検索」で検索してみます。カスタムヘッダで「X-Spam-Level」を追加して「**」で検索すると、迷惑メールではないメールがちらほらとヒット。「***」で検索してみると迷惑メールのみになったので、X-Spam-Levelが3未満のメールをケータイに転送する事にしました。

.mailfilterに以下を設定。

if ( ! ( /^X-Spam-Level: *{3,}/ ) )
{
        cc "!ケータイのメールアドレス"
}

これでめでたく迷惑メールでないメールだけがケータイに転送されるようになりました。

の、 はずだったのですが、それでも次々に転送されてくる迷惑メール。どのメールも、件名に「=?koi8-r?B?~」とケータイでデコードされない MIME。koi8-rってどこ?(ロシア、でした。)このメールだけはX-Spam-Levelが3以上にならないので、仕方なく個別に転送を拒否します。

if ( ! ( /^X-Spam-Level: *{3,}/ || /^Subject: =?koi8-r?B?/ ) )
{
        cc "!ケータイのメールアドレス"
}

ひとまずこれに落ち着きました。

しばらく経って、少し変更。
ケータイ側のメールサーバの仕様をいまいち把握していなくて、もし何らかの理由でケータイ側のメールサーバに転送メールの受け取りを拒否されると、エラーメールが送信元に行ってしまうなぁ、と。
メールの転送ではよく聞く事例ですが、このエラーメールには転送先のメールアドレスとそれに配送できなかった理由が記載されるので、つまりメールの送信者に転送先の(ケータイの)メールアドレスを知られてしまいます。それが迷惑メール送信者だったらもうサイテーです。

なので、メールを転送する時にenvelope sender、いわゆる送信元(Envelope-FromやSenderとも)を変更する事にしました。

if ( ! ( /^X-Spam-Level: *{3,}/ || /^Subject: =?koi8-r?B?/ ) )
{
        cc "| /usr/sbin/sendmail -i -f 送信元メールアドレス ケータイのメールアドレス"
}

直接ケータイのメールアドレスを指定して転送させるのではなく、メールをsendmailに渡してケータイに送信させます。その際にsendmailの-fオプションで送信元のメールアドレス、つまりエラーメールの送信先とするメールアドレスを指定します。
メールの本文に先頭が.(ドット)の行があってもそのまま転送できるよう-iも指定しています。間違っても-tは付けないように!

これで、配送エラーが発生した場合のエラーメールは、元の送信者に送信される事なく、指定した送信元メールアドレス宛に届くようになりました。(指定するケータイのメールアドレスを存在しないメールアドレスに変えて試してみると確認できます。)メールのループが発生しないよう、送信元メールアドレスには転送設定をしない別のメールアドレスを指定しましょう。