AWS Chaliceを使ってFileMaker用のメール受信APIを作る
(2022年11月25日追記)
私の本が株式会社インプレス R&Dさんより出版されました。この記事の内容も含まれています。イラストは鍋料理さんの作品です。猫のモデルはなんとうちのコです!
感想を書いていただけるととても嬉しいです!
(2022年8月3日追記)この記事の内容はこちらの本でも読めます。
先日、はじめてPyPIにPythonライブラリを登録した話を書きましたが、そもそも何のためにライブラリを登録したかという話をします。
背景
FileMakerにはメールを送信する機能はありますが、受信する機能はありません。しかし業務用アプリを作っていると、メールの情報をDBに取り込んで処理したい場面は結構出てきます。メール受信機能のように、標準装備されていない機能をFileMakerで実現する方法は、大きく分けてふたつあります。ひとつはプラグインをインストールする方法で、もうひとつはAPIなどを利用して外部システムと連携させる方法です。メールを受信するためのプラグインとしてはMailitや360worksあたりが有名です。外部システムとの連携は、検索するといくつか出てきますが、今のところ定番と呼べるようなサービスはなさそうです。
弊社では私が数年前にPythonで開発したメール受信APIを利用してメールをFileMakerに取り込んでいます。それ以前はMailitプラグインを利用していました。ほかにも自社開発したAPIはいくつかあって、中には「これは販売したら売れるんじゃない?」と思えるものもあります。今までは忙しくてAPIの販売に踏み切れませんでしたが、今年前半は比較的余裕があるので、APIを販売してみることにしました。
APIを販売するには、販売するためのプラットフォームが必要です。既存の仕組みだとAWS MarketplaceやRakuten RapidAPIがありますが、どちらもいまいち好きになれなかったので、プラットフォームごと自社開発することにしました。弊社はフロントエンドの技術が弱いので、これを機にReactを学びながら作ってみる予定です。そうすればスキルも付きますし、なによりおもしろいですからね。
フロント側はこれから数か月かけて作るとして、バックエンドのAPIは先に作ってテストしておいた方がよさそうだと思い、準備することにしました。社内向けと違って一般販売を視野に入れたAPIを開発するには下記のようにクリアすべき課題がいくつかあります。
- 認証は必須
- APIの利用制限は必要
- 利用者が増えたら自動でスケールするようにしたい
- 利用がないときにはお金がかからないようにしたい
以上を踏まえると必然的にクラウド上でサーバーレス運用する方針になるかと思います。GCPにするかAWSにするかでかなり悩みましたが、利用制限を簡単にかけられることが決め手となってAWSを利用することにしました。
メール受信APIの仕様
今回実装するメール受信APIの機能はこの2つです。
- IMAP4サーバーからメールを取得し、JSON形式にして返す
- 指定された日数より前のメールをサーバーから削除する
リクエストパラメーターとレスポンスはそれぞれ以下の通りです。
メール受信機能のリクエストパラメーター
リクエストパラメーターのキー | 説明 |
---|---|
host_name | IMAP4サーバーのホスト名。 |
user_id | IMAP4アカウントのユーザーID。 |
password | IMAP4アカウントのパスワード。 |
search_option | 省略可。IMAP4の検索オプション。省略時はUNSEEN が設定され、未読メッセージのみが取得対象となる。 |
timezone | 省略可。クライアントのタイムゾーン。省略時はAsia/Tokyo が設定される。 |
メール受信機能のレスポンス
レスポンスのキー | 説明 |
---|---|
messages | メッセージのデータが配列で格納される。 |
messages[n].subject | メッセージのタイトル。 |
messages[n].body | メッセージ本文。 |
messages[n].from | メッセージのFrom。 |
messages[n].to | メッセージのTo。 |
messages[n].cc | メッセージのCC。 |
messages[n].date | メッセージの送信日付。 |
messages[n].time | メッセージの送信時刻。 |
messages[n].format | メッセージのフォーマット(text/plainもしくはtext/html)。 |
messages[n].msg_id | メッセージID。 |
messages[n].charset | 文字コード(utf-8など)。 |
messages[n].header | メッセージのヘッダー。 |
messages[n].attachments | 添付ファイルのデータが配列で格納される。 |
messages[n].attachments[m].file_name | 添付ファイルのファイル名。 |
messages[n].attachments[m].file_obj | 添付ファイルのオブジェクトがbase64エンコードされたテキストデータ。 |
メール削除機能のリクエストパラメーター
リクエストパラメーターのキー | 説明 |
---|---|
host_name | IMAP4サーバーのホスト名。 |
user_id | IMAP4アカウントのユーザーID。 |
password | IMAP4アカウントのパスワード。 |
days | 省略可。数値型で日数を指定するとIMAP4サーバー上からその日数より前に届いたメッセージが削除される。省略時は90が設定される。 |
メール削除機能のレスポンス
レスポンスのキー | 説明 |
---|---|
delete_count | 削除したメッセージの件数。 |
APIの実装
APIはAWSのLambdaとAPI Gatewayを用いて実装します。普通にLambda Functionを書いても良いのですが、Chaliceを使うととても簡単に実装できます。Chaliceの使い方はこちらのハンズオン記事がわかりやすいです。
メール受信APIのソースコードはこちらです。
import json
from chalice import Chalice
from imap2dict import MailClient
app = Chalice(app_name='fm_mail_backend')
@app.route('/fetch_mail', methods=['POST'], api_key_required=True)
def fetch_mail():
# リクエストパラメータの解析
request_params = app.current_request.json_body
# hostname, user_id, passwordは必須
host_name = request_params['host_name']
user_id = request_params['user_id']
password = request_params['password']
# search_optionとtimezoneは省略可能
search_option = request_params['search_option'] if 'search_option' in request_params else 'UNSEEN'
timezone = request_params['timezone'] if 'timezone' in request_params else 'Asia/Tokyo'
# メールを受信
cli = MailClient(host_name, user_id, password)
messages = cli.fetch_mail(search_option=search_option, timezone=timezone)
resp = {
'status':'OK',
'messages':messages
}
# 結果を返す
return json.dumps(resp, ensure_ascii=False)
@app.route('/delete_mail', methods=['DELETE'], api_key_required=True)
def delete_mail():
# リクエストパラメータの解析
request_params = app.current_request.json_body
# hostname, user_id, passwordは必須
host_name = request_params['host_name']
user_id = request_params['user_id']
password = request_params['password']
# daysは省略可能
days = request_params['days'] if 'days' in request_params else 90
# メールを削除
cli = MailClient(host_name, user_id, password)
delete_count = cli.delete_mail(days=days)
# 結果を返す
return {"delete_count":delete_count}
面倒くさい部分をすべてimap2dict
ライブラリに追い出したおかげで、こんなにシンプルに書くことができました。たったこれだけの記述でメール受信と削除の機能を実現できるって、すごくないですか?
これをしたいがために前回の記事でPyPIにライブラリを登録したわけです。ようやく冒頭部分につながりました。
後はchalice deploy
でデプロイして、API GatewayにAPIキーを設定すればAPI本体は完成です。LambdaとAPI Gatewayの連携やIAMのロールなどはChaliceが自動で良い感じに設定してくれます。バックエンドとしてはAPIキーの自動発行やユーザー管理などを作り込む必要がありますが、そのあたりはおいおい作っていきます。
FileMaker側のサンプルアプリ
APIができたので実際にFileMakerから接続してみます。サンプルアプリはこちらからダウンロードできます。
右上の歯車アイコンをクリックすると設定画面が開きます。
「FM Mail」というのはサービスの名前(仮称)です。すべての項目を設定して「新着メール受信」ボタンをクリックすると下図のようにメールと添付ファイルに対応したレコードが作られます。
日本語の添付ファイル名も文字化けせずに読み込めていますね。
サービス公開に向けて
弊社の業務用アプリは数週間前から実際にAWS上のAPIに接続して運用しています。切り替えのときは緊張しましたが、今のところまったく問題なく動いていて、かえって気持ち悪いです。
API販売プラットフォームの実装とサービス公開にはあと数か月はかかると思いますが、進捗状況はその都度記事にして公開していく予定です。
Discussion