AWS Lambdaで静的サイトにメール送信フォームを作る簡単な方法

Share
AWS Lambdaで静的サイトにメール送信フォームを作る簡単な方法

AWS Lambdaで静的サイトにメール送信フォームを作る簡単な方法

本稿では個人的に作ったLambda用メール送信スクリプトを使ってメール送信フォームを作る方法をご紹介する。手っ取り早く知りたい方はGitHubに公開したソースコードをご覧頂きたい。

今はgitさえ使えればGitHub PagesやNetlifyで無料で静的なサイトを公開できる。便利な世の中だ。静的サイトとはサーバサイドを含まない単純なサイトのこと。自分のホームページやMarkdownノートアプリのサイトも全部Netlifyで配信している。速いし安定していてすごく気に入っている。

Netlifyで運用しているMarkdownノートアプリのサイト https://www.inkdrop.app/

静的サイトはサーバサイドを含まないので、自前で動的にページを生成したりフォームを設置することが出来ない。でもちょこっとだけそういう事がしたいというユースケースがあると思う。例えばホームページに問い合わせフォームを設置するとか。問題は、わざわざそのためだけにNetlifyの有料機能を使ったりサーバを設置するのは大げさだし面倒という点。いつくるか分からない問い合わせのためだけに、ずっとサーバをスタンバイさせるのは無駄。

サーバレスアーキテクチャはこういう「ちょい足し用途」にとても適している。必要な時に必要なリソースだけ割り当ててサーバを動かせる。例えばAWS Lambdaは動作時間と割当リソースのサイズで料金が決まるので、待っている間は料金がかからない。

今回作った問い合わせフォーム

今回、AWS Lambdaを使って自分のホームページに問い合わせフォームを設置してみた。ソースコードをGitHubに公開したので、これを元にすればすぐにあなたもメール送信APIが作れる。AWS Lambdaを使ってみたいという人には良いチュートリアルになると思う。

APIのアーキテクチャ

Lambdaは処理ごとに “function” を作って呼び出して使う。functionそれ自体はAWS上で動く単なるスクリプト。node.jsやJava、C#、Pythonが動かせる。SES(Simple Email Service)はAWSが提供するメール送信サービス。後述するけど簡単にメールが送れるので、構える必要はない。Lambda functionからこのSESを通じてメールを送信する。ただし、Lambda functionはデフォルトでは外部に公開されないので、自身のサイトから呼び出すにはHTTPエンドポイントを付けてやる必要がある。そしてAPI Gatewayがそれを担う。以上のアーキテクチャの概略を上図に示した。

このLambda functionはAWS標準で提供されている方法だととても煩雑で管理しづらい。その問題を解決するためにapexというツールを使う。apexの概要は以下の記事が参考になるだろう。

apexをインストールする:

<span id="6d56" class="ri pi io re b gz rj rk m rl rm">curl https://raw.githubusercontent.com/apex/apex/master/install.sh | sh</span>

次に、AWSのアクセスキーが環境にセットアップ済みであることを確認する。apexは以下の環境変数を使用する。

  • AWS_ACCESS_KEY_ID — AWSアカウントアクセスキー
  • AWS_SECRET_ACCESS_KEY — AWSアカウントシークレットキー
  • AWS_REGION — AWSリージョン

もしまだされていなければ、こちらを参考に設定する。次に、apexプロジェクトの初期化を行う。今回使用するスクリプト群をgitでcloneして、その中で初期化する:

<span id="6bab" class="ri pi io re b gz rj rk m rl rm">git clone <a class="ag hb" href="mailto:git@github.com" rel="noopener ugc nofollow" target="_blank">git@github.com</a>:craftzdog/send-email-lambda.git<br></br>cd send-email-lambda<br></br>apex init<br></br>> Project name: send-email</span>

プロジェクト名は send-emailとする。するとapexがプロジェクト名に倣ってIAM roleなどを自動で作成してくれて、project.json というファイルが生成される。このファイルを以下のように編集する。

<span id="2f86" class="ri pi io re b gz rj rk m rl rm">{<br></br> "name": "send-email",<br></br> "description": "Simple email transmitter",<br></br> "memory": 128,<br></br> "timeout": 5,<br></br> "environment": {},<br></br> "runtime": "nodejs6.10",<br></br> "role": "<YOUR_IAM_ROLE>"<br></br>}</span>

これでLambdaを使う準備が出来た。

Lambdaを使う準備ができたら、次にメールを送るための準備をする。まずはAWS SESで使いたいメールアドレスを認証して登録する。以下のように、SESの管理画面で “Verify a New Email Address” というボタンを押下する。

使いたいメールアドレスの登録

AWSから認証メールが飛んでくるので、メール内に書かれているリンクを開けば登録が完了。これでSESからそのアドレスを使ってメールが送れるようになった。

次に、Lambda functionからそのアドレスで送るように設定する。 functions/submit/function.json というファイルを開いて以下のように編集する。

<span id="df6c" class="ri pi io re b gz rj rk m rl rm">{<br></br> "environment": {<br></br> "SES_REGION": "us-west-2",<br></br> "FROM_NAME": "Craftzdog Contact Form",<br></br> "FROM_EMAIL": "<YOUR_AUTOMATED_EMAIL_SENDER>",<br></br> "TO_EMAIL": "<EMAIL_TO_RECEIVE>"<br></br> }<br></br>}</span>

  • SES_REGION: SESを使うリージョン。Oregonならus-west-2。
  • FROM_NAME: 送り元の名前。 “俺の問い合わせフォーム” とか。
  • contact@example.com
  • TO_EMAIL: 問い合わせを受け取りたいメールアドレス

Lambdaを使って誰かに好き放題されないように、標準では最低限の権限しかapexのIAMロールに与えられていない。SESを使いたいので、その権限を与えるポリシーを追加する。

IAMの管理画面に行って、apexが作成したロールを見つける。以下の画像ではロールの名前が contact-form_lambda_function となっているけど、あなたは send-email_lambda_function となっているはず。

“Create Role Policy”というボタンを押して、以下ようなポリシーを作成する。名前は send-email_submit にする。

<span id="8931" class="ri pi io re b gz rj rk m rl rm">{<br></br> "Version": "2012-10-17",<br></br> "Statement": [<br></br> {<br></br> "Sid": "Stmt1504526549000",<br></br> "Effect": "Allow",<br></br> "Action": [<br></br> "ses:SendEmail"<br></br> ],<br></br> "Resource": [<br></br> "*"<br></br> ]<br></br> }<br></br> ]<br></br>}</span>

これで送信する準備が整った。早速送ってみよう。以下のコマンドで直接Lambda functionを呼び出せる。

<span id="f994" class="ri pi io re b gz rj rk m rl rm">echo -n '{ "subject": "hello", "body": "world" }' | apex invoke submit</span>

件名が “hello” 本文が “world” のメールがあなたの受信ボックスに届いたら成功。おめでとう!もし来なければ、以下のコマンドでログを確認する。

<span id="da91" class="ri pi io re b gz rj rk m rl rm">apex logs -f</span>

エラーメッセージを読んで、正しくロールにポリシーが適用されているか、AWSのリージョンを間違えていないか、送信元メールアドレスは正しくSESに認証されているかなどを確認する。

さて、Lambda functionが用意できたがこれをサイトから呼び出せるようにしたい。そのためにAPI GatewayでHTTPエンドポイントを作成する。日本語だとこのあたりが参考になる。

/submit に対する POST メソッドのリクエストを受け取って、 Lambda functionを呼び出すように設定する。

“Create API” でAPIを新規作成する。名前は “my-awesome-send-email-api”とか。

Resoueces セクションにて、 “Actions” -> “Create Resource” を選択して /submit リソースを作成する。この時、 “Enable API Gateway CORS” にチェックを入れる。

作成した /submit エンドポイントに対して、 POST メソッドを受け付けるようにする。 “Actions” -> “Create Method” でメソッドを作成する。

メソッドの設定

上図のようにLambda functionを呼び出すように設定する。

APIの作成結果

準備ができたら、APIをインターネットに公開する。 “Actions” -> “Deploy API” を選択して APIをデプロイする。デプロイの名前は “production” とか。

これで以下のように、APIを外から呼び出せるようになった。

デプロイ結果

画面上部に表示されている Invoke URL というやつがAPIのエントリーポイント。curlで以下のように呼び出せる。

<span id="bf80" class="ri pi io re b gz rj rk m rl rm">curl --request POST \<br></br> --url <a class="ag hb" href="https://qen9yylar9.execute-api.us-west-1.amazonaws.com/production/submit" rel="noopener ugc nofollow" target="_blank">https://******.execute-api.us-west-1.amazonaws.com/production/submit</a> \<br></br> --header 'content-type: application/json' \<br></br> --data '{<br></br> "subject": "Hello",<br></br> "body": "Hoge"<br></br>}'</span>

メールが届いたら成功。おめでとう!

いたずらで大量にメールが送られたりしないように、呼び出し回数を制限しておくことをお勧めする。上記の画面で、 “Enable throttling” にチェックを入れて、 “Rate” の欄に 1とか2 と入力しておけばOK。

これはお好きな方法でいいと思うけど、HTML5 標準の fetch 関数を使う方法を紹介する。以下のような関数を作ればいい:

<span id="f1a8" class="ri pi io re b gz rj rk m rl rm">export default function sendEmail (subject, body) {<br></br> return fetch('<a class="ag hb" href="https://qen9yylar9.execute-api.us-west-1.amazonaws.com/production/submit'" rel="noopener ugc nofollow" target="_blank">https://******.execute-api.us-west-1.amazonaws.com/production/submit'</a>, {<br></br> method: 'POST',<br></br> headers: {<br></br> 'Accept': 'application/json',<br></br> 'Content-Type': 'application/json'<br></br> },<br></br> body: JSON.stringify({ subject, body })<br></br> })<br></br>}</span>

これでサイトからメールが送れるようになった。やったね!あとは入力された情報から件名や本文をJSで生成して、この関数を叩けばOK。

今回紹介したようなメールフォームは、例えばお店や会社のシンプルなホームページとかに付け足すのに最適だと思う。賢く作ればサーバ代がほぼゼロで運用できる上に多少凝ったことも出来る。S3やDynamoDBと組み合わせればコメント欄も付けられる。DynamoDBもLambdaと同じで完全に従量課金制なので、ちょい足し利用にはもってこい。もしまた機会があればその方法も紹介したいと思う。参考になったらClapお願いします!

Netlifyはいつからかは分かりませんが、現在はフォームハンドリング機能を無料で提供しているようです。なんと、NetlifyのファウンダーのMathias Biilmannに英語版ブログのコメント欄で教えてもらいました:

Great guide to using lambda, these kind of cloud functions are a really great way to glue different services together without relying on a bloated, monolithic, dynamic backend.Small note, though, form handling on Netlify is completely free currently, so no need for a paid plan to enable it. You can basically get this whole setup + comment spam filtering, just by adding a netlify attribute to your HTML form :)

— Mathias Biilmann (強調は筆者)

メールフォームを設置するだけならもはやAWS Lambdaすら不要ですね。Google Formsの代替としてとても強力な選択肢と言えます。

作ってます: https://www.inkdrop.app/

Read more

個人開発で日本から海外へ、10年間の歴史 — ひろしさんとの対談(前編)

個人開発で日本から海外へ、10年間の歴史 — ひろしさんとの対談(前編)

数週間前、ひろしさんのポッドキャストにゲストで出演しました。お互いの長い個人開発の経験について語り合いました。英語版を作成する過程で、日本語でも綺麗に整形した書き起こしが出来たので、こちらに掲載します。お楽しみください。 ※ギアアイコンをクリックして、音声と字幕を日本語に変更できます。 00:00 イントロ:TAKUYAさんようこそ 01:32 TAKUYAさんの自己紹介:WalknoteからInkdropまで 04:54 独立への踏み切り方:慎重派と勢い派 06:51 個人開発がフリーランス案件につながった 09:17 Inkdropで食えるようになるまで 12:15 なぜ最初から海外市場を狙ったのか 14:54 AI登場前、英語コピーに苦戦した話 16:18 AIバイブコーディング時代をどう見ているか 17:24 全てのコードを一行ずつレビューする使い方 21:06 AIは新幹線:速さの先にあるもの 25:53 AI時代に「感性」が大事になる 27:

By Takuya Matsuyama
「一汁一菜」にAI時代の生き方が詰まっている

「一汁一菜」にAI時代の生き方が詰まっている

どうも個人アプリ作家のTAKUYAです。 今回は、AI時代を開発者・クリエイター・表現者としてどう健やかに生きるか、について考えていることをシェアしたいと思います。ここでの「健やかに生きる」とは、心身の健康を保ちながら、ものづくりを楽しみ続けるという意味です。 読者の中にも、最近のAIの急速な進化の中でどう生き残り、さらに活躍していくかを悩んでいる方は多いのではないでしょうか。正直、すべてに対する正解はわかりません。未来を正確に予測できる人はいないからです。 でも自分は、ソフトウェア寄りのアーティストとして生きる上で大事なのは、「戦略」や「堀(moat)」を築くことよりも、「生きる方向性」 だと思っています。 人生とは速度ではなく方向である – ゲーテ 自分はどこに行きたいのか?何を見たいのか?それが大事です。戦略は状況に合わせて柔軟に変えればいいからです。 今回は、日本の文化からいくつかの生き方の原則を探ってみたいと思います。 最近、料理研究家の 土井善晴 さんの 「一汁一菜でよいという提案」 を読んで、日々のリズムを健やかに保つためのヒントがたくさん詰まっていると感じまし

By Takuya Matsuyama
Claude Codeをtmuxのポップアップウィンドウで継続的に走らせる方法

Claude Codeをtmuxのポップアップウィンドウで継続的に走らせる方法

💡本記事は英語ブログの日本語訳です。 どうも、TAKUYAです。 AIコーディングでは専らClaude Codeを使っています。最初はtmuxでターミナルの右側にペインを分割して使っていたのですが、幅が狭すぎてメッセージやdiffがまともに表示できず、使いづらかったです。 <Prefix>+zでペインを最大化すればいいのですが、毎回やるのは面倒でした。 そこで、ポップアップウィンドウでClaude Codeを起動するようにしました。キーバインドを押せばセッションが開き、閉じてもバックグラウンドで動き続けるので、すぐに再開できます。 この記事では、それを実現するためのtmuxの設定方法を紹介します。 動画で見る(英語): ポップアップウィンドウはサブプロセスを維持できない tmuxのdisplay-popupコマンドを使うとポップアップウィンドウを表示でき、ちょっとしたツールにすぐアクセスするのに便利です。 僕はlazygitでgitの状態をサッと確認するのに使っています: bind -r g display-popup -d '#{pane_current_path}'

By Takuya Matsuyama
Keychron K2 HEを無刻印化する手順

Keychron K2 HEを無刻印化する手順

どうもTAKUYAです。KeychronさんにK2 HEをお願いしたら音速で送ってくれたので、無刻印化してみました。どうやったのか過程をシェアします。 Unboxing 上はKeychron Q1です。これは3年間ぐらい使ってきました。キーキャップが若干くたびれていますね。でも問題なく今まで使えていました。そろそろ飽きてきたので新しいキーボードを試したいと思い、前から気になっていたK2 HEを試すことにしました(写真下)。 Amazon | 【国内正規品】Keychron K2 HE ラピッドトリガー ワイヤレス カスタムキーボード、ホールエフェクトGateronダブルレール・マグネットスイッチ、2.4GHz・Bluetooth無線対応、QMKプログラム可能、アルミ+ウッドフレーム、USレイアウト、RGBライト、Mac Windows Linux対応 (ブラック) | Keychron | パソコン用キーボード 通販【国内正規品】Keychron K2 HE ラピッドトリガー ワイヤレス カスタムキーボード、ホールエフェクトGateronダブルレール・マグネットスイッチ、

By Takuya Matsuyama