FIELD NOTES: 書を持って街へ出よう

合同会社フィールドワークス プログラマ兼代表のブログ

Google Apps Script でメールをタイマー送信する方法

メールの送信を予約して,決まった日時に送りたいことがあります。

そのようなことを実現するためのアプリケーションもあるようですが,常にPCの電源を入れておく必要があります。
一方,外部のASPサービス(「ステップメールサービス」など)も存在するようですが,有料であったり,無料であってもメール本文に広告が入ったりするので,気軽に使うことができません。

そこで,Google Apps Script を使ってメールのタイマー送信を実現してみました。

スプレッドシートの作成

まずは,Googleドキュメントでスプレッドシートを作成します。
シートを一つ追加し,「template」と「schedule」という名前に変更します。

templateシートには,2行目以降にメールの件名と,メール本文のテンプレートを記入します。
件名またはメール本文中の「${ … }」という文字列は,メール送信時に可変のパラメータに置き換えられます。

f:id:fet:20120117164330j:image:w640

scheduleシートには,送信予定日時,テンプレートの番号,宛名,メールアドレスを記入します。
templateシートの2行目のテンプレートがテンプレート番号1に対応します。

f:id:fet:20120117164331j:image:w640

スクリプトの作成

次にスクリプトを作成します。

「ツール/スクリプトエディタ…」メニューを選択し,コードを入力します。

変数BCCには,BCCの送信先を設定します。
不要であれば,空文字列にしてください。

/**
 * Send mail according to a schedule.
 * スケジュールに合わせて自動でメールを送信する。
 *
 * Created by: Field Works, LLC / 合同会社フィールドワークス
 * Reference: http://www.field-works.co.jp/
 * Date: 2012/01/17
 */

var BCC = 'admin@sample.com';

function format(templ, params) {
  return templ.replace(/\${(.*?)}/g, function($0, $1) {
    return (params[$1] && typeof(params[$1]) != "object") ?
      params[$1].toString() : JSON.stringify(params[$1]);
  });
}

// メール本文を取得する
function getMessage(ss, row, params) {
  var templ = ss.getSheetByName('template');
  var r = templ.getRange('A2:B99');
  var subject = r.getCell(row, 1).getValue();
  var body = r.getCell(row, 2).getValue();
  return {subject: format(subject, params), body: format(body, params)};
}

// メール送信
function sendEMail(to, subject, body, opt) {
  try {
    MailApp.sendEmail(to, subject, body, opt);
  } catch (e) {
    return {result: 'NG', message: e.message};
  }
  return {result: 'OK', message: ""};
}

// 送信スケジュールをチェックする
function checkSchedule() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var schedule = ss.getSheetByName('schedule');
  var r = schedule.getRange('A2:F999');
  var row = r.getNumRows();
  var now = (new Date()).getTime();
  for (var i = 1; i <= row; ++i) {
    // 「送信予定日時」が空ならデータの終わりと判断
    if (r.getCell(i, 1).getValue() == "") {
      break;
    }
    var tm = r.getCell(i, 1).getValue().getTime();
    var status = r.getCell(i, 5).getValue();
    if (status == "" && tm < now) {
      // メール送信
      var no = r.getCell(i, 2).getValue();
      var to =  r.getCell(i, 4).getValue();
      var params = {
        TO: r.getCell(i, 3).getValue(),
      };
      var msg = getMessage(ss, no, params);
      var ret = sendEMail(to, msg.subject, msg.body, {bcc: BCC});
      // 処理結果を書き込み
      r.getCell(i, 5).setValue(ret.result);
      r.getCell(i, 6).setValue(ret.message);
    }
  }
}

トリガーの設定

「トリガー/現在のスクリプトのトリガー…」メニューを選択して,タイマートリガーを設定します。
ここでは,15分毎にチェックするように設定しました。

f:id:fet:20120117164332p:image:w640

現在時刻が「送信予定日時」を超えるとメールを送信し,処理結果を「結果」欄に設定します。
メール送信処理中に例外が発生した場合は,「エラーメッセージ」欄に例外メッセージを残します。

IPAmj明朝フォントの研究 ― 実装編 ―

前回の調査結果を元に Field Reports 1.4 に以下の機能を盛り込みました。

fet2011-12-23

サロゲートペア対応

従来は,PDFで定義済みのCMapである「UniJIS-UCS2-H」を使ってエンコーディングを行なっていましたが,これでは1文字=2バイトのコードまでしか対応できませんでした。

そこで,フォントファイルが存在する場合はエンコーディングとして「Identity-H」を使用することにしました。
Identity-Hの場合,文字コードは(0〜65,535)のCIDベースになります(TrueTypeフォントの場合はGID)。
UnicodeからCIDへの変換は,フォント自身が持っているcmapを使って行います。

これで,サロゲートペアで表現される文字もCIDまたはGIDに変換して,PDFに埋め込むことができるようになりました。

ただし,プログラミング言語によっては2バイトを超えるUnicode文字をエスケープシーケンスなどで表現できないので,数値参照文字も使えるようにしました。

&#dddd; または &#xhhhh; (ddddは10進数,hhhhは16進数)

ついでに,CIDまたはGIDで直接グリフを指定できるよう「グリフ参照文字」も使えるようにしました。

&@#dddd; または &@#xhhhh;l

異体字セレクタ

異体字セレクタ(IVS)の情報は,フォントファイルのcmapテーブルの中の「Format 14 」のサブテーブルに格納されています。

Field Reports は内部的には文字コードをUCS4で持っています。UCS4をCIDまたはGIDに変換する際に1文字先読みし,2文字目が異体字セレクタ(0x0E0100〜0x0E01EF)であれば,IVSを使って変換するようにしました。

グリフ名参照

前回触れたとおり,IPAmj明朝フォントの場合「post」テーブルにグリフ名→GIDの対応表が収納されています。

文字参照を独自拡張した「グリフ名参照」により,グリフ名を指定できるようにしました。
以下のような書式になります。

&@<グリフ名>;

使用例

以下に,サロゲートペア・異体字セレクタ・グリフ名参照を使用してPDFを作成した例を示します。

実行には,Field Reports のコマンドラインプログラムを使用しました。
下記のパラメータファイルを作成してコマンドラインプログラムに掛けると,先頭の実行例の様なPDFが作成されます。

サロゲートペア」では,Unicode 6.0に含まれるCJK統合漢字拡張漢字B集合〜D集合の文字の一部を表示しています。

異体字セレクタ」では,異体字セレクタを使って「邊」の異体字等を表示しています。

「グリフ名参照文字」では,IPAmj明朝に収納されている文字のうちUCSが未実装かつIVS実装されていない7,160文字の一部を表示しています。

{
    "resources": {
        "font": {
            "IPAmjMincho": {
                "path": "./ipamjm.ttf",
                "embed": true,
                "subset": true
            }
        }
    },

    "template": {"size": "A4"},

    "context": {
        "text": [
            {
                "new": "Tx",
                "font": "IPAmjMincho",
                "font-size": 14,
                "rect": [50, 750, 550, 780],
                "value": "【サロゲートペア】"
            },
            {
                "new": "Tx",
                "font": "IPAmjMincho",
                "font-size": 24,
                "multiline": true,
                "rect": [50, 650, 550, 750],
                "charref": true,
                "value": "&#x2000B;&#x20089;&#x200A2;&#x200A4;&#x201A2;
&#x20213;&#x2032B;&#x20371;&#x20381;&#x203F9;&#x2044A;&#x20509;
&#x205D6;&#x20628;&#x2074F;&#x20807;&#x2083A;&#x208B9;&#x2097C;
&#x2099D;\n&#x2A716;&#x2A729;&#x2a72a;&#x2a72c;&#x2a738;&#x2a73d;
&#x2a746;&#x2a752;&#x2a758;&#x2a75f;\n&#x2B740;&#x2B741;&#x2B742;
&#x2B743;&#x2B744;&#x2B745;&#x2B746;&#x2B747;&#x2B749;&#x2B74A;
&#x2B74C;&#x2B74D;"
            },
            {
                "new": "Tx",
                "font": "IPAmjMincho",
                "font-size": 14,
                "rect": [50, 600, 550, 630],
                "value": "【異体字セレクタ】"
            },
            {
                "new": "Tx",
                "font": "IPAmjMincho",
                "font-size": 24,
                "multiline": true,
                "rect": [50, 500, 550, 600],
                "value": "\u9089\U000E010F\u9089\U000E0119\u9089\U000E011B
\u9089\U000E011A\u9089\U000E011C\u9089\U000E011D\u9089\U000E0117
\u9089\U000E0116\u9089\U000E0115\u9089\U000E0114\u9089\U000E0118
\u9089\U000E0113\u9089\U000E0112\u9089\U000E0111\u9089\U000E0110\n
\u908A\U000E0108\u908A\U000E0109\u908A\U000E010A\u908A\U000E010B
\u908A\U000E010C\u908A\U000E010D\u908A\U000E010E\u908A\U000E010F
\u908A\U000E0110\n葛飾区 葛\U000E0102城市/蓮田市 蓮\U000E0104田市"
            },
            {
                "new": "Tx",
                "font": "IPAmjMincho",
                "font-size": 14,
                "rect": [50, 450, 550, 480],
                "value": "【グリフ名参照文字】"
            },
            {
                "new": "Tx",
                "font": "IPAmjMincho",
                "font-size": 24,
                "multiline": true,
                "rect": [50, 350, 550, 450],
                "charref": true,
                "value":"&@mj000007;&@mj000008;&@mj000012;&@mj000022;&@mj000023;
&@mj000028;&@mj000029;&@mj000036;&@mj000037;&@mj000045;&@mj000046;
&@mj000047;&@mj000048;&@mj000073;&@mj000074;&@mj000089;&@mj000105;
&@mj000106;&@mj000129;&@mj000130;&@mj000143;&@mj000144;&@mj000145;
&@mj000146;&@mj000156;&@mj000157;&@mj000175;&@mj000176;&@mj000183;
&@mj000184;&@mj000185;&@mj000206;&@mj000207;&@mj000208;&@mj000209;
&@mj000241;&@mj000242;&@mj000264;&@mj000265;&@mj000266;&@mj000267;
&@mj000269;&@mj000270;&@mj000276;&@mj000277;&@mj000278;&@mj000302;
&@mj000303;&@mj000309;&@mj000310;&@mj000311;&@mj000312;&@mj000317;
&@mj000318;&@mj000332;&@mj000333;&@mj000380;&@mj000381;&@mj000405;
&@mj000406;"
            }
        ]
    }
}

Jimdoでソースコードを整形して表示するならPygmentsが便利

Webサイトにソースコードを整形して貼り付ける時の定番は,SyntaxHighlighterのようです。
ただ,SyntaxHighlighter付属のCSSファイルをサイトにアップロードする必要があり,Jimdoで使うのはちょっと面倒なので躊躇していました。

先日,Pygmentsというソフトを見つけたので試してみました。

Pygmentsとは

Pythonで作成された“syntax highlighter”で,Sphinx, rts2pdf, Trac, GitHubなど様々なプロダクトで使用されています。

以下の出力形式に対応しています。

  • HTML
  • ANSI sequences (console output)
  • LaTeX
  • RTF

また,入力として受付可能なプログラミング言語が非常に多く,OCamlにも対応しているのがポイント高いです。

インストール

easy_installがインストールされていれば,pigmentsのインストールは非常に簡単です。

$ sudo easy_install pygments

使い方

pigmentsをインストールすると,pygmentizeというコマンドラインプログラムが作られます。

以下のように実行すると,HTMLのコード片が作成されます。

$ pygmentize -f html -l ruby -o foo.html foo.rb

出力されたHTMLを表示するのに必要なスタイル指定は,以下のコマンドで作成できます。
`default'スタイルでは,61行のコンパクトなCSSが出力されました。

$ pygmentize -S default -f html > pygments.css

スタイル指定を含んだHTMLを出力したい場合は`-O full'オプションを付けます。

$ pygmentize -f html -O full -l ruby -o foo.html foo.rb

Jimdoでの設定

CSSの設定

Jimdoの管理画面の「独自画面/CSS」に,先ほど作成したCSSの中身をペーストします。

ソースコードの貼りつけ

ソースコードを貼りつけたい場所で「ウィジェット」を追加し,pygmentizeで作成したHTMLをペーストします。

fet2011-12-21

IPAmj明朝フォントの研究

独立行政法人情報処理推進機構IPA)より「IPAmj明朝フォント」が公開され,6万字というインパクトもあり,各所で注目されているようです。

弊社で開発している「PDF帳票開発ツール Field Reports」でもこのフォントが自由に使えるようになれば,利便性が高まりそうです。どうやったらこの6万字をフルに活用できるのか,調べてみました。

文字コレクション

IPAのプレス発表にも書いてあるとおり,このフォントは行政機関向け(もっと言えば人名用)に作成されたフォントです。

 氏名には多様な漢字が使われており、国、地方公共団体等の行政機関では、情報システムで適切に氏名を扱うために、コンピューターに標準搭載されていない文字を外字として作成するなど、正しく氏名を表記するための様々な取り組みを行ってきました。しかし、氏名を正確に表記したいという要望がある一方で、外字の作成や管理の手間などが、大きな課題となっていました。
 そこでIPAでは、経済産業省委託事業「文字情報基盤構築に関する研究開発事業」において、行政機関の情報システムで、人名等の漢字を効率的に扱う基盤のあり方について検討するとともに、各組織での共通基盤として利用可能な文字フォントの作成を行い、IPAmj明朝フォントの検証版として公開しました。

通常,メイリオヒラギノなどの汎用目的に作成されたフォントはJIS2004Adobe-Japan1などの文字コレクションにもとづいていますが,IPAmjフォントは「戸籍統一文字」「住民基本台帳ネットワークシステム統一文字」をベースとした以下の文字が収録されています。
* 戸籍統一文字(55,267字)
* 住民基本台帳ネットワーク システム統一文字(19,432字)
* JIS漢字コード(10,050字)
* 常用漢字(2,136字)

ただ,第一水準〜第四水準の文字数の合計と一致するので,「JIS漢字コード(10,050字)」はJIS 2004に対応していると考えられます。
汎用目的に使用しても特に問題はなさそうに思えます。

上記を全て包含する 漢字58712 文字 +かな+欧文文字+記号類 = 約6万字。正確には60,718字が収録されています。OpenTypeフォントの仕様上の限界が6,5536字なので,限界近くまで収録されていることがわかります。

符号化

http://ossipedia.ipa.go.jp/ipamjfont/mjmojiichiran/index.html で文字情報の一覧表を見ることができます。

58,712字の漢字のうちUnicodeが割り当てられている(「UCS実装」に○が付いている)文字は49,278字であり,残りの9,434文字はUnicodeが割り当てられていません。
その他,JISに属してる文字は「句点番号」,戸籍統一文字は「戸籍統一文字番号」,住民基本台帳ネットワークシステム統一文字は「住基ネット統一文字コード」といったようにそれぞれ文字コレクションでのコードが併記されていますが,いずれもすべてをカバーすることができません。

そこでIPAでは,"MJ"+6桁数字で表記される「MJ文字図形名」というコードを定義してグリフを管理しているようです。

グリフの呼び出し方

では,この6万字をフルに活用するためにはどうすればよいでしょうか?

Unicodeによるグリフ指定

現在のコンピュータでIPAmj明朝フォントを利用するには,Unicodeを使用するのが便利です。
ただし,Unicode 1.0時代の1文字=16ビットという素朴な仕様で利用できる範囲を超えていますので,49,278字を利用するには以下の仕様に対応したOSやアプリケーションが必要になります。

UTF16で21ビットのコードを表現するには2文字分必要になりますので,これを「サロゲートペア」と呼びます。
UCS実装済みの文字については,Unicodeで直接よびだすことができます。

異体字セレクタ(IVS)」とは,例えば渡邊の「邊」のように復数の字形を持つ文字において「基底文字+異体字セレクタ」の組み合わせでグリフを区別する方法です。IPAmj明朝フォントでは,4,193字にIVSが割り当てられています。
例えば,異体字が多いことで有名な渡邊の「邊」に対応する文字は「文字情報一覧表」に16文字あります。このうち,「IVS実装」に「○」が付いている15文字については異体字セレクタを使って区別して呼び出すことができます。
f:id:fet:20111212115840p:image:w640

GIDによるグリフ指定

UCSが未実装かつIVS実装されていない残りの7,1617,160文字を呼び出すためには,Unicode以外の方法を使う必要があります。次に考えられるのは,GIDを直接使ってグリフを指定する方法です。GIDというのは,TrueType内部でのグリフの管理番号であり,0〜65,535の整数値が割り当てられます。

ただ,GIDは内部管理番号なのでフォントにより体系が異なります。
PostScript系のCIDフォントであれば,アドビが“Adobe-Japan1”で定義したCIDにより指定することができますが,TrueType系のフォントはグリフとGIDの対応表が公開されていなければ実質使えません。また,Adobe-Japan1に準拠しているわけではないので,CIDと対応付けるのも無理な話です。

また,残念ながら「文字情報一覧表」にはGIDは記載されていません。
技術的にはGIDとグリフの一覧をダンプすることも可能ですが,検索するのが大変そうです(実用にならないでしょう)。
UCS未実装の9,434字かつIVS実装の7,160文字は実質利用することができないのでしょうか?

グリフ名によるグリフ指定

そこでIPAに問い合わせてみたところ,有力な情報を教えて頂けました。
TrueTypeフォントファイルの“post”テーブルに「グリフ名」とGIDの対応表が収納されているとのことです。

postテーブルは,PostScript系フォントの互換のために残されているテーブルという頭があったので盲点でした。
試しにpostテーブルをダンプしてみると,確かに全グリフ分のグリフ名が収録されていました。以下に,Apple社が配布している「The Apple Font Tool Suite」を使ってpostテーブルをダンプした結果の一部を示します。グリフ名はMJ文字図形名に対応した「"mj"(小文字)+6桁数字」となっています。

                <PostScriptName glyphRefID="3160" NameString="mj001194" />
                <PostScriptName glyphRefID="3161" NameString="mj001195" />
                <PostScriptName glyphRefID="3162" NameString="mj001196" />
                <PostScriptName glyphRefID="3163" NameString="mj001197" />
                <PostScriptName glyphRefID="3164" NameString="mj001198" />
                <PostScriptName glyphRefID="3165" NameString="mj001199" />
                <PostScriptName glyphRefID="3166" NameString="mj001200" />
                <PostScriptName glyphRefID="3167" NameString="mj001202" />
                <PostScriptName glyphRefID="3168" NameString="mj001203" />
                <PostScriptName glyphRefID="3169" NameString="mj001204" />
                <PostScriptName glyphRefID="3170" NameString="mj001205" />
                <PostScriptName glyphRefID="3171" NameString="mj001206" />
                <PostScriptName glyphRefID="3172" NameString="mj001207" />
                <PostScriptName glyphRefID="3173" NameString="mj001208" />
                <PostScriptName glyphRefID="3174" NameString="mj001209" />
                <PostScriptName glyphRefID="3175" NameString="mj001210" />
                <PostScriptName glyphRefID="3176" NameString="mj001211" />
                <PostScriptName glyphRefID="3177" NameString="mj001212" />
                <PostScriptName glyphRefID="3178" NameString="mj001213" />

アプリケーションにグリフ名で文字を呼び出す機能があれば,IPAmj明朝フォントのすべてのグリフを活用できそうです。

Field Reportsでの対応

以上の調査結果を元に,現在開発中のPDF帳票開発ツールField Reports 1.4では,以下の機能を盛り込む予定です。
これだけ用意しておけば,IPAmj明朝フォント以外の多くのグリフを収録したフォントでも利用できるのではないでしょうか?

  • 21ビットコードポイント(サロゲートペア)対応
  • 異体字セレクタ対応
  • GID/CIDによるグリフ指定
  • グリフ名によるグリフ指定
  • PDFへのフォントの埋込
2011.12.19 追記

Field Reports 1.4では,実体参照風の書式によりグリフ名参照ができるようになりました。

    &@<グリフ名>;