読者です 読者をやめる 読者になる 読者になる

Google talkでメールを送るスクリプト

perl

会社の人とか、よくメッセンジャー使う人とかとのやり取りはメッセンジャー使えば良いんだけど、
僕の周りはPC立ち上げていない人の方が多く、たいてい携帯でメールが飛んできます。


で、僕はPC立ち上げてるので携帯にメール来たらそれをPCから返したいなって思ったりしてました。
ちまちま携帯で返すよりもサクッとキーボード打ちたかったりするわけです。
昔はPCのメーラ立ち上げてメールしたりもしたんだけど、
ちょっと面倒だし、せっかくメッセンジャー立ち上がってるならそれ使えたらいいなと。


ググってみたんだけど、そういうアプリ見つからなかったので勉強兼ねて作ってみました。


手順は

  1. メールを送る役割をしてくれるgoogle talkユーザのアカウントをとる
    • 例えばexample@gmail.comとか
  2. 上で作ったアカウントにアクセスするgoogle talkユーザを決める
    • これはいつも自分が使ってるアカウント。例えばmy@gmail.comとか
    • 一応セキュリティ上、操作できるクライアントを決めておいた方よさそうなので。
  3. 自分の携帯アドレスを登録
    • 携帯に返信来て欲しいので。例えばmobile@t.vodafone.ne.jpとか。
  4. 自分の友達のメアドと、それにわかりやすい名前をつけたもののマッピングを作る
    • 例えばfriend1@t.vodafone.ne.jpって友達はfriend1とか
  5. これらをYAMLファイルに書いて、google talkのクライアントになるperlがそれを読み込み起動する
  6. で、「@名前」と先頭につけて空白で区切った後にメッセージ投げるとそのユーザへメールが送られる
    • 「@friend1 こんにちは」ならfriend1@t.vodafone.ne.jpに「こんにちは」が送られる
    • 複数人に送りたかったら「@friend1 @friend2 こんにちは」とやる

まずperlのコード(gtail.pl)

#!usr/local/bin/perl

use strict;
use warnings;

use utf8;
use AnyEvent;
use Carp;
use Encode;
use Email::MIME;
use Email::MIME::Creator;
use Email::Send;
use Net::XMPP2::IM::Connection;
use Net::XMPP2::IM::Roster;
use Net::XMPP2::IM::Message;
use YAML::Syck;

use Data::Dumper;
use Devel::Peek;

my $yaml = 'gtalk.yml';
my $conf = YAML::Syck::LoadFile($yaml);

my $j = AnyEvent->condvar;
my $con = Net::XMPP2::IM::Connection->new(
    %{$conf->{login}},

    #override_host => 'talk.google.com',
    resource => "Net::XMPP2"
);

$con->reg_cb(
    session_ready => sub {
        my ($con) = @_;
        print 'Connected as ' . $con->{username} . "\n";
        my $immsg = Net::XMPP2::IM::Message->new (    # 毎回うざければ送信しない
            body => 'こんにちは',
            to   => $conf->{address}->{_owner},
        );
        $immsg->send($con);
    },
    message => sub {
        my ($con, $msg) = @_;
        # ownerのクライアントからじゃないと操作できないように
        return if $msg->from !~ m/ ^$conf->{address}->{_owner} /xms;

        my @body = split /[\s]+/, $msg->any_body; # body is flagged utf8
        my @users;
        while (1) {
            last if $body[0] !~ m{ ^@(.*) }xms; # @がついてる限りuser

            push @users, $1;
            shift @body;
        }
        my $reply = $msg->make_reply;
        $reply->add_body("send failure.");
        my $res = (@users) ? send_mail(\@users, join ' ', @body) : undef;
        $reply->add_body("send to @users: @body")
            if $res && $res->type eq 'success';
        $reply->send;

        print "Message from " . $msg->from . ":\n"
            . encode('utf-8', join ' ', @body) . "\n---\n";
    },
);

print "Trying to connect...\n";
$con->connect;
$j->wait;

sub send_mail {
    my ($users_ref, $body) = @_;
    my $from = $conf->{address}->{_from};
    my $to = convert_address($users_ref) || return; # 当てはまるアドレスなければundef

    warn "send to $to\n";
    warn "body: $body\n";

    # http://perl-users.jp/modern_introduction_perl/email_send.html
    # メールオブジェクトをつくる
    my $mail = Email::MIME->create(
        header => [
            From    => $from,
            To      => $to,
            #Subject => encode('MIME-Header-ISO_2022_JP', 'subject'),
        ],
        attributes => { charset => 'iso-2022-jp' }, # ないと文字化ける
        parts => [
            encode('iso-2022-jp', $body),
        ],
    );

    # Email::Send で送信する
    my $sender = Email::Send->new({ mailer => 'Sendmail' });
    $sender->send($mail);
}

sub convert_address {
    my $users_ref = shift;
    my %address = %{$conf->{address}};
    my @addresses = @address{@$users_ref} || return; # yamlにアドレスがなければundef

    my $to = join ',', map {
        (ref $_ eq 'ARRAY') ? join ',', @$_ : $_;
    } @addresses;

    return $to;
}

で、これを起動させるためのyamlファイル(gtalk.yml)

login:
  username: example
  password: example
  domain: gmail.com
address:
  _owner: my@gmail.com
  _from: mobile@t.vodafone.ne.jp
  friend1: friend1@t.vodafone.ne.jp
  friend2: friend2@t.vodafone.ne.jp
  group1:
    - friend1@t.vodafone.ne.jp
    - docomo@docomo.ne.jp


MLみたいにも使いたかったので、グループも指定できるようにした。
上のYAMLの場合だと、「@group1 明日の予定は?」ってメッセージ投げると、friend1@t.vodafone.ne.jpとdocomo@docomo.ne.jpに「明日の予定は?」ってメールが飛ぶ。


とりあえず作ってみたのだけど、相手が「なりすましメール拒否」とかしてると届かないのよね。何かどっかがサービス作ってくれたらいいのにとか思いつつ、そんな個人情報駄々漏れになりそうなの誰も使わないかなと思ったり。


もっとがんばってモジュールとかにして初CodeReposへコミットしてみようかと思ったのだけど、時間がなかったのと、まだコミットのルールをちゃんとわかってないのでまぁいいかとまた先延ばし。