Publish::Plamail::2話
いろいろやってみた。
その甲斐あって、メールが発信できるようになった。
やったぜ!
タイトルも内容も添付できないようになっちゃったけどな。
とりあえず文法的には問題ないと思うので、Publish::Gmailとどう違うのかじっくりと較べてみようと思う。(仕事中に)
俺Pla
いろんなとこからコピペしてPublish::Plamailとかでっちあげてみた。
package Plagger::Plugin::Publish::Plamail;
use strict;
use base qw( Plagger::Plugin );
use DateTime;
use DateTime::Format::Mail;
use Encode;
use Encode::MIME::Header;
use HTML::Entities;
use HTML::Parser;
use Jcode;
use MIME::Lite;
our %TLSConn;
sub rule_hook { 'publish.feed' }
sub register {
my($self, $context) = @_;
$context->register_hook(
$self,
'publish.init' => \&initialize,
'publish.feed' => \¬ify,
);
}
sub init {
my $self = shift;
$self->SUPER::init(@_);
$self->conf->{mailto} or Plagger->context->error("mailto is required");
$self->conf->{mailfrom} ||= 'plagger@localhost';
}
sub initialize {
my($self,$context) = @_;
# authenticate POP before SMTP
if (my $conf = $self->conf->{pop3}) {
require Net::POP3;
my $pop = Net::POP3->new($conf->{host});
if ($pop->apop($conf->{username}, $conf->{password})) {
$context->log(info => 'APOP login succeed');
} elsif ($pop->login($conf->{username}, $conf->{password})) {
$context->log(info => 'POP3 login succeed');
} else {
$context->log(error => 'POP3 login error');
}
$pop->quit;
}
}
sub notify {
my($self, $context, $args) = @_;
return if $args->{feed}->count == 0;
my $feed = $args->{feed};
my $subject = $feed->title || '(no-title)';
my @enclosure_cb;
if ($self->conf->{attach_enclosures}) {
for my $entry ($args->{feed}->entries) {
push @enclosure_cb, $self->prepare_enclosures($entry);
}
}
my $body = $self->templatize('plamail_notify.tt', { feed => $feed });
my $cfg = $self->conf;
$context->log(info => "Sending $subject to $cfg->{mailto}");
my $feed_title = $feed->title;
$feed_title =~ tr/,//d;
my $now = Plagger::Date->now(timezone => $context->conf->{timezone});
my $msg = MIME::Lite->new(
Date => $now->format('Mail'),
From => encode('MIME-Header-ISO_2022_JP', qq("$feed_title" <$cfg->{mailfrom}>)),
To => $cfg->{mailto},
Subject => encode('MIME-Header-ISO_2022_JP', $subject),
Type => 'text/plain; charset=iso-2022-jp',
Encoding=> '7bit',
Data => encode_body($args->{entry}->body),
);
$msg->replace("X-Mailer" => "Plagger/$Plagger::VERSION");
# $msg->attach(
# Type => 'text/html; charset=utf-8',#'text/html; charset=utf-8'
# Data => encode("utf-8", $body),#("utf-8", $body)
# Encoding => 'quoted-printable',
# );
for my $cb (@enclosure_cb) {
$cb->($msg);
}
my $route = $cfg->{mailroute} || { via => 'smtp', host => 'localhost' };
$route->{via} ||= 'smtp';
eval {
if ($route->{via} eq 'smtp_tls') {
$self->{tls_args} = [
$route->{host},
User => $route->{username},
Password => $route->{password},
Port => $route->{port} || 587,
];
$msg->send_by_smtp_tls(@{ $self->{tls_args} });
} elsif ($route->{via} eq 'sendmail') {
my %param = (FromSender => "<$cfg->{mailfrom}>");
$param{Sendmail} = $route->{command} if defined $route->{command};
$msg->send('sendmail', %param);
} else {
my @args = $route->{host} ? ($route->{host}) : ();
$msg->send($route->{via}, @args);
}
};
if ($@) {
$context->log(error => "Error while sending emails: $@");
}
}
sub encode_body {
my $str = shift;
$str = remove_utf8_flag($str);
$str =~ s/\x0D\x0A/\n/g;
$str =~ tr/\r/\n/;
return Jcode->new($str, guess_encoding($str))->jis;
}
sub guess_encoding {
my $str = shift;
my $enc = Jcode::getcode($str) || 'euc';
$enc = 'euc' if $enc eq 'ascii' || $enc eq 'binary';
return $enc;
}
sub remove_utf8_flag { pack 'C0A*', $_[0] }
sub prepare_enclosures {
my($self, $entry) = @_;
if (grep $_->is_inline, $entry->enclosures) {
# replace inline enclosures to cid: entities
my %url2enclosure = map { $_->url => $_ } $entry->enclosures;
my $output;
my $p = HTML::Parser->new(api_version => 3);
$p->handler( default => sub { $output .= $_[0] }, "text" );
$p->handler( start => sub {
my($tag, $attr, $attrseq, $text) = @_;
# TODO: use HTML::Tagset?
if (my $url = $attr->{src}) {
if (my $enclosure = $url2enclosure{$url}) {
$attr->{src} = "cid:" . $self->enclosure_id($enclosure);
}
$output .= $self->generate_tag($tag, $attr, $attrseq);
} else {
$output .= $text;
}
}, "tag, attr, attrseq, text");
$p->parse($entry->body);
$p->eof;
$entry->body($output);
}
return sub {
my $msg = shift;
for my $enclosure (grep $_->local_path, $entry->enclosures) {
my %param = (
Type => $enclosure->type,
Path => $enclosure->local_path,
Filename => $enclosure->filename,
);
if ($enclosure->is_inline) {
$param{Id} = '<' . $self->enclosure_id($enclosure) . '>';
$param{Disposition} = 'inline';
} else {
$param{Disposition} = 'attachment';
}
$msg->attach(%param);
}
}
}
sub generate_tag {
my($self, $tag, $attr, $attrseq) = @_;
return "<$tag " .
join(' ', map { $_ eq '/' ? '/' : sprintf qq(%s="%s"), $_, encode_entities($attr->{$_}, q(<>"')) } @$attrseq) .
'>';
}
sub enclosure_id {
my($self, $enclosure) = @_;
return Digest::MD5::md5_hex($enclosure->url->as_string) . '@Plagger';
}
sub DESTORY {
my $self = shift;
return unless $self->{tls_args};
my $conn_key = join "|", @{ $self->{tls_args} };
eval {
local $SIG{__WARN__} = sub { };
$TLSConn{$conn_key} && $TLSConn{$conn_key}->quit;
};
1;
Can't call method "body" on an undefined value
とか出て動かねえよばーかばーか。
ぐすん。
Publish::Iso_2022_jp_mailその後
コピペして実行してみたら、えらいことモジュールが足りなかったので、CPANからダウンロードしてみた。
なんかCPAN.pmとかってモジュール使うと便利にインストールできるみたいだけど、怖いのでフル手動。
グリグリドラッグしてやったもんね。
Missing right curly or square bracket at /Users/USER/Plagger-Mac-0.7.11-2/CPAN/lib/perl5/site_perl/Plagger/Plugin/Filter/FormatText.pm line 1, at end of line
なんだこれ。
カッコが足りないとか言われてるみたい。
だけどなんのことかわからん。
確かに僕はカッコ悪いかもしれないが、
外見をけなすのはいけない事だって先生も言ってたぞ。
Publish::Iso_2022_jp_mail
あっ、これからやろうとしてる事がこんなとこ(→s_nobuの日記 - Publish::Iso_2022_jp_mail)に完成形で。
Type => 'text/plain; charset=ISO-8859-1'
転んでも泣かない。
できたぜ。
携帯から読めるようになったぜ。
結果から言えば、テキストエンコードがUTF-8になってたから読めなかった。
テンプレートは関係なかった。
でも、結局はテンプレートいじらないとソースコード垂れ流しで読みにくいのでごっそり削って、
[% USE util = Plagger.Util -%] [% FOREACH entry = feed.entries -%] [% entry.body %] [%- END %]
とかにしちゃったんだけどな。
エンコード変更は、Publish::Gmailの89,90行目を、怖いもの知らずにも直接書き換えてやったわ。
ぬわははは。
怖いよー。
$msg->attach(
Type => 'text/plain; charset=ISO-8859-1',
Data => encode("ISO-8859-1", $body),
Encoding => 'quoted-printable',
赤字のとこな
えー、頑張ってみましたが、ここで詰みです。
このままだと、万能Plaggerは僕の携帯にしかメールを送れない貧弱君になってしまいます。
gmail_notify.ttを書き換えるだけだったら、ファイル名をちょこちょこ打ち変えればなんとか運用できそうなんですけど、Publish::Gmailを書き換えるのはダメだ。色々怖すぎる。モジュールの中身をいじくっちゃなんねえってラクダに言われたような気もするし。
元に戻そう。