EvernoteにTSV(CSV)ファイルをインポートするPerlスクリプトを書いた

久しぶりにPerl書いたら楽しかった。

目的はEvernoteにTSVファイル(タブ区切りのファイル)をインポートすること。

TSVファイルの1番目がノート名、2番目がノートの内容となるようにする。

ノート名1\tノートの内容1

ノート名2\tノートの内容2

...

最初はEvernoteAPIを使ってやろうとしたけど、 キーを申請してから取得するまで時間がかかるようなので断念。

調べていると以下の記事を見つけた。

AppleScriptを使ってTSV(CSV)からEvernoteにインポートしてみた | あのねちょう

コピペしてみたけどうまく動かない。 これを機にAppleScriptを勉強してみるか、と思ったけど 取り急ぎEvernoteにTSVファイルをインポートしたいだけなので断念。

ここで、Evernoteはメールからでもノートを作成できる機能があることを思い出した。 ということはメールさえ送信できればどんな言語でも良いことになる。

そこで、スクリプト言語で一番書き慣れているPerlで書くことにした。

#!/usr/bin/perl

use strict;
use warnings;
use utf8;
use Encode qw/decode encode/;
use MIME::Base64;
use Email::MIME;
use Email::Sender::Transport::SMTP::TLS;
use Email::Sender::Simple 'sendmail';
use Try::Tiny;

# Evernoteの投稿用メールアドレス
my $evernote_mail = 'foo@m.evernote.com';
# Evernoteの投稿先ノートブック名
my $notebook = 'notebook_name';
# 読み込むTSVファイル名
my $csv_file = 'file.tsv';
# Gmailのメールアドレス
my $gmail_addr = 'bar@gmail.com';
# Gmailのパスワード(二段階認証の場合はアプリケーション固有のパスワード)
my $gmail_pass = 'password';
# Gmailのホスト名
my $gmail_host = 'smtp.gmail.com';
# Gmailのポート番号
my $gmail_port = 587;

open my $fh, '<', $csv_file
  or die qq/Can't open file "$csv_file" : $!/;

my $cnt = 0;

print "Upload notes to Notebook: \"".encode('utf8', $notebook)."\".\n";

while ( <$fh> ) {
    my $line = $_;
    chomp($line);
    my ($note_title, $note_content) = split("\t", $line);
    print "Upload note: \"".decode('utf8',encode('utf8', $note_title))."\" ... ";
    # メールの件名に "@ノートブック名" でそのノートブックに追加される
    send_gmail(sprintf("%02d", $cnt + 1).'. '.decode('utf8', $note_title).' @'.$notebook,
               decode('utf8', $note_content));
    print "done.\n";
    $cnt++;
    sleep 10;
}

print "Uploaded $cnt notes.\n";

close $fh;

exit;

# Gmailを送信
sub send_gmail {
    my $subject = shift;
    my $body    = shift;

    # メール作成
    my $email = Email::MIME->create(
      header => [
        From    => encode('MIME-Header-ISO_2022_JP' => $gmail_addr),
        To      => encode('MIME-Header-ISO_2022_JP' => $evernote_mail),
        Subject => encode('MIME-Header-ISO_2022_JP' => $subject),
      ],
      attributes => {
        content_type => 'text/plain',
        charset      => 'ISO-2022-JP',
        encoding     => '7bit',
      },
      body => encode('iso-2022-jp' => $body),
    );

    # SMTP接続設定
    my $transport = Email::Sender::Transport::SMTP::TLS->new(
    {
        host     => $gmail_host,
        port     => $gmail_port,
        username => $gmail_addr,
        password => $gmail_pass,
    }
    );

    # メール送信
    try {
    sendmail($email, {'transport' => $transport});
    } catch {
    my $e = shift;
    die "Error: $e";
    };
}

Gmailのホスト名、ポート名は基本そのままで、それ以外の変数を環境に応じて変更する。 読み込むTSVファイルはスクリプトと同じディレクトリに置く。 CSVの場合は、以下の部分を変更すれば良い。

    my ($note_title, $note_content) = split("\t", $line); # TSV
    my ($note_title, $note_content) = split(",", $line); # CSV

単純な割に結構いろんなモジュール使ってるけど、 それらは全部cpanmでさくっとインストールした。cpanm超便利。

App::cpanminus - search.cpan.org

perlモジュールのinstallにcpanmを使う|perl|@OMAKASE

とりあえず、50件程度のインポートはうまくいった。 メールの送信にGmailを利用しているので、 あんまり件数が多すぎるとGoogleにスパム扱いされそう…。

スパム扱いされてアカウントがロックされたりするのがこわいので、 1件送信するごとに10秒のスリープを入れている。 なので、大量のデータだとかなり時間かかる。

はまった点

Gmailの認証ではじかれる

スクリプトを動かすと認証でエラーを吐く。 ポートを変えたりしてもダメ。

以下のようなメールがきていることに気づく。

Google アカウント: ログイン試行をブロックしました

Googleが気を利かせてブロックしてくれたらしい。

メールに書いてあるとおり、安全性の低いアプリのアクセスを許可すればメール送信できた。

Evernoteのノート名が文字化けする

最初はUTF-8でやろうとしてたけど、件名に日本語を入れるのはまずいっぽい。 そこで、以下のサイトの通りにやったらうまくいった。

第20回 Email::Sender:メールを送信する:モダンPerlの世界へようこそ|gihyo.jp … 技術評論社