Perlでgmailからメール送る 補足

とりあえずメールは送れたが、中身が何やってるか全然分からんので、もう少し調べてみた。

その1 Conent-Typeなどの属性情報

Email::Simpleだとheaderとbodyしか使われず、attributesに指定したContent-Typeなどのパラメーターは無視されてしまうようです。

my $email = Email::Simple->create(
  header     => [
    From    => 'kobayashi01234@gmail.com',
    To      => 'kobayashi01234@gmail.com',
    Subject => encode("MIME-Header-ISO_2022_JP", "テストメール"),
  ],
    attributes => {
      content_type => 'text/plain',
      charset      => 'ISO-2022-JP',
      encoding     => '7bit',
    },
    body => encode('iso-2022-jp', "てすと"),
);

print $email->as_string;
From: kobayashi01234@gmail.com
To: kobayashi01234@gmail.com
Subject: =?ISO-2022-JP?B?GyRCJUYlOSVIJWEhPCVrGyhC?=
Date: Thu, 20 Feb 2014 13:24:50 +0900

てすと

MIME形式でメールを作成すれば(当然だけど)ちゃんと付く。

my $email = Email::MIME->create(
  header     => [
    From    => 'kobayashi01234@gmail.com',
    To      => 'kobayashi01234@gmail.com',
    Subject => encode("MIME-Header-ISO_2022_JP", "テストメール"),
  ],
    attributes => {
      content_type => 'text/plain',
      charset      => 'ISO-2022-JP',
      encoding     => '7bit',
    },
    body => encode('iso-2022-jp', "てすと"),
);

print $email->as_string;
From: kobayashi01234@gmail.com
To: kobayashi01234@gmail.com
Subject: =?ISO-2022-JP?B?GyRCJUYlOSVIJWEhPCVrGyhC?=
Date: Thu, 20 Feb 2014 13:26:55 +0900
MIME-Version: 1.0
Content-Type: text/plain; charset="ISO-2022-JP"
Content-Transfer-Encoding: 7bit

てすと

マルチパートじゃないメールでも明示的にContent-Typeを指定しておいたほうがよいのだろうか。とりあえずGmailからGmailに送る分にはEmail::Simpleのままで文字化けも起こっていないようだし、OKということにしよう。

その2 EMAIL_SENDER_TRANSPORT 環境変数

このあたりのサイトに色々と説明がされているんだけど、よく分からん。

調べてみた結果、環境変数 EMAIL_SENDER_TRANSPORT=XXX を指定すると、メールの送信に "Email::Sender::Transport::XXX" モジュールが使われる、ということらしい。で、XXXモジュールは何してるのかというと、send_emailを呼び出してるだけのようです(だけ、ということも無いんだろうけど)。

# Email/Sender/Role/CommonSending.pm:

sub send {
  my ($self, $message, $env, @rest) = @_;
  my $email    = $self->prepare_email($message);
  my $envelope = $self->prepare_envelope($env);

  try {
    return $self->send_email($email, $envelope, @rest);
  } catch {
    Carp::confess('unknown error') unless my $err = $_;

    if (
      try { $err->isa('Email::Sender::Failure') }
      and ! (my @tmp = $err->recipients)
    ) {
      $err->_set_recipients([ @{ $envelope->{to} } ]);
    }

    die $err;
  }
}

EMAIL_SENDER_TRANSPORT = Print を指定するとメールの中身をprintしてくれる。

# Email/Sender/Transport/Print.pm:

sub send_email {
  my ($self, $email, $env) = @_;

  my $fh = $self->fh;

  $fh->printf("ENVELOPE TO  : %s\n", join(q{, }, @{ $env->{to} }) || '-');
  $fh->printf("ENVELOPE FROM: %s\n", defined $env->{from} ? $env->{from} : '-');
  $fh->print(q{-} x 10 . " begin message\n");

  $fh->print( $email->as_string );

  $fh->print(q{-} x 10 . " end message\n");

  return $self->success;
}
$ EMAIL_SENDER_TRANSPORT=Print perl sm.pl
ENVELOPE TO  : kobayashi01234@gmail.com
ENVELOPE FROM: kobayashi01234@gmail.com
---------- begin message
From: kobayashi01234@gmail.com
To: kobayashi01234@gmail.com
Subject: =?ISO-2022-JP?B?GyRCJUYlOSVIJWEhPCVrGyhC?=
Date: Thu, 20 Feb 2014 13:46:21 +0900

てすと
---------- end message

EMAIL_SENDER_TRANSPORT = Test の使い方がサッパリ分からんかったけど、どうやら擬似的にエラーを発生させたりするものらしい。delivery_failure と recipient_failure を上書きすると送信を失敗させられるよ!超簡単だね!みたいなこと書いてあるが、別に簡単でもないような・・・。

BEGIN {
  use Email::Sender::Transport::Test;
  $ENV{EMAIL_SENDER_TRANSPORT} = 'Test';
  no warnings 'redefine';
  *Email::Sender::Transport::Test::delivery_failure  = sub {Email::Sender::Failure::->new("Error1")};
}

my $email = Email::Simple->create(
  header     => [
    From    => 'kobayashi01234@gmail.com',
    To      => 'kobayashi01234@gmail.com',
    Subject => encode("MIME-Header-ISO_2022_JP", "テストメール"),
  ],
  body => encode('iso-2022-jp', "てすと"),
);

sendmail($email);
$ perl sm.pl
Error1

Trace begun at /usr/lib/perl5/site_perl/5.14/Email/Sender/Transport/Test.pm line 86
Email::Sender::Transport::Test::send_email('Email::Sender::Transport::Test=HASH(0x60106b6a0)', 'Email::Abstract=ARRAY(0x60105e230)', 'HASH(0x60105e1e8)') called at /usr/lib/perl5/site_perl/5.14/Email/Sender/Role/CommonSending.pm line 47
Email::Sender::Role::CommonSending::try {...}  at /usr/lib/perl5/site_perl/5.14/Try/Tiny.pm line 81
eval {...} at /usr/lib/perl5/site_perl/5.14/Try/Tiny.pm line 72
Try::Tiny::try('CODE(0x601189678)', 'Try::Tiny::Catch=REF(0x601018838)') called at /usr/lib/perl5/site_perl/5.14/Email/Sender/Role/CommonSending.pm line 60
Email::Sender::Role::CommonSending::send('Email::Sender::Transport::Test=HASH(0x60106b6a0)', 'Email::Abstract=ARRAY(0x60105e230)', 'HASH(0x6011897c8)') called at /usr/lib/perl5/site_perl/5.14/Email/Sender/Simple.pm line 121
Email::Sender::Simple::send_email('Email::Sender::Simple', 'Email::Abstract=ARRAY(0x60105e230)', 'HASH(0x60105e140)') called at /usr/lib/perl5/site_perl/5.14/Email/Sender/Role/CommonSending.pm line 47
Email::Sender::Role::CommonSending::try {...}  at /usr/lib/perl5/site_perl/5.14/Try/Tiny.pm line 81
eval {...} at /usr/lib/perl5/site_perl/5.14/Try/Tiny.pm line 72
Try::Tiny::try('CODE(0x60105e200)', 'Try::Tiny::Catch=REF(0x600baf8d0)') called at /usr/lib/perl5/site_perl/5.14/Email/Sender/Role/CommonSending.pm line 60
Email::Sender::Role::CommonSending::send('Email::Sender::Simple', 'Email::Simple=HASH(0x60105e128)') called at /usr/lib/perl5/site_perl/5.14/Sub/Exporter/Util.pm line 18
Sub::Exporter::Util::__ANON__('Email::Simple=HASH(0x60105e128)') called at sm.pl line 36

こんな使い方でいいのかなあ・・・?よく分からん。

その3 Email::Sender::Transport::SMTP::TLS

POD見るとEmail::Sender::Transport::SMTPSの方がオススメだからそっち使え、と書いてあるのでそうした方がよいかもしれない。