mizzsugar’s blog

日々感じていることや学んだことを書きます。エンジニアリング以外にも書くかもしれません。

JevでStackChan-LikeなゲームをPythonで作ってみた

最近話題のJevを学ぶために、ゲームを作ってみました。

docs.typesafe.ai

以前Pyladies Shizuokaに参加したときに、StackChanというAI連携可能なデスクトップロボットが話題になりました。やはりハードなだけあって2万円近くと手を出しにくい値段だったので、PyxelでStackChanみたいな見た目のキャラに話しかけると表情が変わるゲームを作りました。 (動画はリポジトリのREADMEに添付しています)

github.com

要件

  • Pyxelでロボット風のキャラクターを表示する(画面・目・口・アンテナのあるスタックチャン風の見た目)
  • キーボードで話しかけたい言葉を英語で入力できる。ポップアップやIMEには頼らず、ゲーム画面1つで完結させる
  • 入力内容をJevに渡し、「褒め言葉」「愚痴」「悲しい話」「面白い話」「その他」の5パターンに分類してもらう
  • 分類結果に応じて表情(喜怒哀楽+通常)を切り替える。「その他」は相槌を打つような、うなずきモーションを追加
  • キャラは表情を返すだけでセリフは返さない。会話の記憶も持たせず、毎回の入力を独立に判定する

「学習」や「対話」の要素は思い切って捨て、判定エンジンとしてJevを1回呼ぶだけの、なるべくシンプルな構成にしました。本家StackChanは音声認識・音声合成・実機のサーボモーターまで備えていますが、今回はそのうち「話しかけると表情が変わる」という核だけを、PC上のソフトウェアだけで再現した形です。

処理フロー

なぜLLMではなくJevにしたのか

今回のように「入力を数個のカテゴリに振り分けるだけ」のタスクに、汎用LLMのフル機能(長文生成や多ターン対話)はオーバースペックでJevの使いどころでは…?と考えました。

Jevは2026年9月にTypeSafe AIが発表した、テキストを生成しない専用モデルです。TypeSafe自身は「System Oneモデル」と呼んでいます。プログラムの状態を受け取り、型付きの決定を確率つきで1回で返す設計で、フロンティアLLMより40〜200倍高速、入力100万トークンあたり0.042ドル(出力は無料)とされています。TypeSafeが公開しているPongのデモでは、同じ12秒間にJevは47回の判定を返したのに対し、対話用LLMは2〜3回だったそうです*1。ゲームのように「入力のたびに即座に反応がほしい」用途とは相性が良いと感じました。

従来のテキスト分類比べると手軽

もう一つの比較対象が、BERTなどをfine-tuningする従来のテキスト分類です。こちらはtransformersなどのライブラリでラベル付き学習データ(最低でも各カテゴリ数十〜数百件)を用意し、GPU環境で学習を回し、精度を評価し、カテゴリを変えるたびに再学習する必要があります。個人のちょっとした制作でこの工程をこなすのは、正直ハードルが高いです。

JevのSystem One APIは、この工程を丸ごと「カテゴリを自然言語で説明する」だけに置き換えてくれます。後述のコードのようにcriteriaという辞書に説明文を書くだけで、その場で分類器が動きます。学習データもGPUも不要で、判定基準を変えたければ辞書の文字列を書き換えるだけです。精度でfine-tuning済みモデルに勝るという話ではなく、学習データを集める工数ゼロで「動くもの」がすぐ作れる、プロトタイピングの速さが魅力だと思いました。

PythonのSDKを使って実装

実装はpip install typesafe-sdkで入るSDKを使います。

from typesafe_sdk import Choice, TypeSafeClient

client = TypeSafeClient()  # TYPESAFE_API_KEY を自動で読み込む

CRITERIA = {
    "smile": "A compliment or something happy and positive.",
    "angry": "A complaint, criticism, or something negative and aggressive.",
    "cry":   "Sad or difficult news.",
    "lol":   "A very funny story or a strong joke.",
    "nod":   "None of the above.",
}

def judge(text: str) -> str:
    if not text.strip():
        return "nod"
    try:
        res = client.system_one(
            state=text,
            questions={"reaction": Choice(
                instructions="Decide how this character should react to what was just said.",
                criteria=CRITERIA,
            )},
        )
        return res.answers["reaction"].choice
    except Exception:
        return "nod"

stateに判定したい文字列をそのまま渡し、Choiceのcriteria辞書のキーがそのまま結果として返ってくるので、Python側はそのまま分岐に使えます。SDKにはChoice(多肢選択)の他に、Yes/No系のNoulや数値スケールのScoreもあり、今回は5表情から1つ選ばせたいのでChoice一択でした。通信失敗時は「あいづち」にフォールバックし、ゲームが落ちないようにしています。

表情の描画自体はPyxelのcircやlineだけで組んだ簡単なドット絵ですが、「あいづち」ではうなずき、「爆笑」では画面が震えるモーションをpyxel.camera()でキャラ全体をずらして表現しています。

REACTION_TO_EXPR = {
    "smile": "joy", "angry": "anger", "cry": "sorrow", "lol": "fun", "nod": "normal",
}

class RobotFaceApp:
    NOD_FRAMES = 24    # うなずきモーションの長さ(フレーム数)
    SHAKE_FRAMES = 36  # 震えモーションの長さ(フレーム数)

    def __init__(self):
        self.input_buffer = ""    # 画面下の入力欄にたまっている文字列
        self.expr = "normal"      # draw_robot()側の表情分岐で使うキー
        self.nod_timer = 0
        self.shake_timer = 0

    def on_enter_pressed(self):
        text = self.input_buffer.strip()
        reaction = judge(text)             # ここで先ほどのJev呼び出しが走る

        self.expr = REACTION_TO_EXPR[reaction]

        self.nod_timer = self.shake_timer = 0
        if reaction == "nod":
            self.nod_timer = self.NOD_FRAMES      # うなずきモーションを開始
        elif reaction == "lol":
            self.shake_timer = self.SHAKE_FRAMES  # 震えモーションを開始

まとめ

「入力をいくつかのカテゴリに振り分ける」程度のタスクなら、汎用LLMより専用の分類モデルの方がコスト・速度の両面で理にかなっています。BERTのfine-tuningと比べても学習データ無しで動かせるので、個人開発のハードルはぐっと下がった気がします。

ただ、今回試したのは日常会話レベルの分類です。専門知識が要る業界特化の判定でどこまで実用的な精度が出るかはまだ未知数で、そこは素直に自前でモデルを作る/fine-tuningする方を検討すべきなのかもしれません。汎用的な用途では十分良さそうという感触はありつつ、専門分野への適用は様子見かなと期待しすぎないように期待しながらウォッチしたいと思います。

*1:ただしこれらの数値はTypeSafe自身の公表値で、第三者による検証ではない点には注意が必要です。また「ハルシネーションしない」というのも、正確には「定義した選択肢以外を物理的に返せない」という意味で、選んだ選択肢自体が常に正しいという保証ではありません。

「Python Web開発実践入門」を読んで

FastAPI本です! 最近はPythonでWeb開発していないのでキャッチアップも兼ねて読みました。

どんな人におすすめか、あったほうが良さそうな前提知識や経験

FastAPIをこれから使う人はもちろん、すでに使ったことのある人にもおすすめです! FastAPIの実践的なプラクティスだけでなく、「こういう仕様だからこう実装する」まで踏み込んでいるため、AIがコードを書き人間が責任を持つ今の時代だからこそ、そこまで踏まえて意思決定するのに必要な知識が書かれているのは有り難いです。

注意してほしい点としては、FastAPIの機能にないという理由でユーザー管理やユーザー用の認証認可には触れていないことです*1。この1冊だけで「ログインしてユーザーがデータを登録・取得するような『よくある』WebAPIを作れる」という訳ではないので別途キャッチアップが必要です。

また、Python経験者含めWebAPIの開発を一度もしたことがない人にはハードルが高いと感じました。「GET」や「パラメータ」など、WebAPIの開発での基本的な用語の説明はないので、その周辺の言葉を聞いて「?」と思った方は少なくとも何かしらのWebFWのチュートリアル*2から開始したほうが良さそうです。これは買わないほうが良いと言いたいわけではありません。1回目読んでわからなくても、経験を積んでしばらくした後に読むと意味がわかることがあるので、未来のためのお守りみたいな感じで持っておくと良い本だと思います。

色々書いたけど、「とりあえず動くものは作れる」よりも先に進みたい人にはぜひおすすめしたいです! 最近拝見した「AIがコードを書くなら、もう勉強しなくていい?AI時代に基礎を学ぶ理由」というスライドに

問題を表現する言葉や、背景にある仕組みを知らなければ、「ここを調べた方がいい」と気づくことすらできないかもしれません

と書いています。本著はFastAPIを用いたWebAPI開発において「この実装は合理的なのか?」「こういうケースで失敗したらどうするか?、どう気づくか?」など問いを立てながらものづくりするための知識の地図のようなものだと思いました。

実践的なプラクティス、仕様にも言及した実装方針の理由

本著は、1〜6章はFastAPIの各機能とその使い方・仕様について言及しています。7章で実際にWebAPI開発をし、8〜10章でエンハンス開発・テスト・クラウド環境へのデプロイをする章立てとなっています。

1〜6章の内容はまず大局を知って早く動くものを作れるようになりたい人にはやや細かい気がしましたが、そういった方は1周目はある程度読み飛ばして写経に徹しても良いかもしれません。 すでにFastAPIを使っている方は、1〜6章から読んでも腹落ちしそうです。

私は1章から順番に読みましたが、1〜6章で「いつも使っているあの機能ってこういう仕様だったのか!」「このユースケースではいつもこう実装しているけど、実はかゆいところに手が届く機能があったのか!」といった気づきを得ました。

特にMiddlewareと非同期IOの箇所が良かったです。仕様を知らないと躓きそうなところに触れつつ細かすぎて読むのが辛いとはなならず、個人的には良いバランスの解説に感じました。

WebAPIの実装にとどまらず、テストやデプロイまでカバー

7〜10章では実際にWebAPIの開発をし、クラウド環境のデプロイしています。開発は1回作りきって終わりなことの方が少ないので、7章で作ったWebAPIの開発を継続する想定で8〜10章が書かれているのは実践的だと思いました。

中でも、8章のエンハンス開発ではBackgroundTasksやWebsocketを使った機能の開発をされており、良い意味で期待を裏切られました。

9章についてはAsycIOを使う前提でのプラクティスが書かれているのが良かったです。pytest前提なので、そちらに興味がある人にもおすすめです。

10章のGoogle Cloudを使ってのデプロイは、多少費用はかかれども比較的小額から始められるし、ある程度スケールしても耐えられそうな構成なのが良かったです。

*1:FastAPIの機能にあるBasic認証には触れています。

*2:FastAPIのチュートリアルもここら辺の用語知ってないとキツそう+最初の一歩としてはやや長いので、DjangoGirlsとかがいいかもしれません。APIではないけど、Webサービス開発の最初の一歩として躓きにくいと思います。

『システム開発と「具体と抽象」』を読んで

具体と抽象をテーマにした著書が多い細谷氏の、システム開発に特化した具体と抽象本です。 もともと他の著書も好きだったのと、自分自身がシステム開発を生業としているので「これは読まねば!」と意気込んで読みました。

https://amzn.asia/d/066C2DSj

↓「具体と抽象 ―世界が変わって見える知性のしくみ」「13歳から鍛える具体と抽象」の感想文↓ mizzsugar.hatenablog.com

AI時代にリーダーを育成する立場として、悩んでいた部分の原因の一部について書かれていたので共感しました。ただ、本著には「どうすれば解決するのか」をあえて明示していないので、明日から行動できるような答えを求めている方には物足りないかもしれません。しかし、AI時代に求められる能力についてぼんやり不安を抱えている人には、どんな背景によってどんな思考が求められているのかヒントを得られるかもしれません。「答えを言われないと動けない」から脱したい人にも刺さるかもしれません。

「言われたことは得意だが、提案が不得意」

本著はSI業界の課題として「言われたことは得意だが提案が不得意」なことを述べています。その要因として、上意下達の業界構造とそれによる「言われたことを言われた通りにやる」ための問題解決型の思考回路を上げています。 今までの業界構造ではそれで問題なかったけれども、企業の系列構造が崩れてきたこととAIの台頭によって変わってきました。提案して仕事を取ってくることが求められるようになり、問題発見型の思考が必要になってきました。

抽象思考で問題発見、具体思考で問題解決

何が問題か、なぜやるのか、など形がないものを扱う問題発見には抽象思考が求められます。一方、どう作るかなどゴールが決まっているものをあつかう問題解決には具体思考が求められます。 抽象ではWhyを問い、具体ではHowを問うともいえます。 抽象思考と具体思考は完全に分かれているのではなく、グラデーションです。ITのPJに例えると抽象的なものから、企画→要件定義→基本設計→詳細設計→実装のように徐々に具体的な内容になっていきます。

グラデーションになっているからこそ、1段階上の抽象度で「なぜこのタスクをやるのか」「この機能の目的は」など考えることが大切です。設計書に書かれていることを着実に実装する前に、「なぜこの機能があるのか」「どんな要望があるのか」など抽象度をあげて目的を考えると、どんなことに考慮して実装やテストをすべきか見えてきて出戻りや考慮漏れが減らせるのではと思いました。

問題発見と問題解決は思考のOSが違う

問題解決型の人材が問題発見型になるのが上手く行かないのは、そもそも思考のOSが違うからだと述べています。いわば、あるPCのOSをMacOSからWindowsOSにリプレースして動くようにしろと言っているようなものです。 それでも問題発見と問題解決を場面によって使い分けないといけません。そのためのイメージモデルとして「メタ化」が提唱されています。1段階上の段階の思考モデルとして下位モデルである具体と抽象を切り替えます。

野球で言うと、問題発見型はピッチャーで課題解決型はキャッチャー。両方同時にやれというのは防具をガチガチに装備しながらボールを上手く投げれないのと同じです。切り替える必要があります。同時にやれと言っているような指示を出さないように気をつけないとなと思いました。

AIが「SIの具体」を代替していく

「ITの進化は抽象度を上げて複雑さを隠す歴史だ」と述べられています。例えばOSはハードの違いという具体を吸収しました。今の時代だと、生成AIは今までに人間が担ってきた設計や実装の一部という具体を肩代わりしつつあります。定義された問題の解決する今までSIがやってきた役割がAIによってコモディティ化してきているからこそ、抽象化し、問題発見し、構造を設計する力が問われます。

リーダー育成を顧みて思ったこと

メンバーとして与えられたタスクを実装・テストする業務が中心だったところからリーダーとして問題を見つけて定義する立場で苦戦するのは、思考のOSが違うから当然なのだと腑に落ちました。

そして、これは生まれ持っての才能に依存する能力ではなく具体と抽象を行き来するトレーニングでカバーできそうな感触があります。例えば、ある業務で受け取ったフィードバックを一般的な教訓に言語化して抽象化し別の業務ではどう行動するか具体で考えることは、どの役職・立場でもすぐにできそうなトレーニングかなと思います。

Pycon mini Shizuoka2026に参加しました

PyCon mini Shizuokaに今年もスタッフとして参加しました。去年は当日スタッフのみでしたが、今年は準備期間から参加しました。

PyCon mini Shizuoka 2026 - connpass

聞いたトーク

生成AI時代に、画像処理やオーディオ処理のノードエディターを作る理由

生成AIで画像処理・オーディオ処理の試行錯誤をできる時代にノードエディターを自作してそれを使って処理をするお話でした。 トークの前はイメージできていなかったのですが、実際に動いているものを見ると、ノードエディターだと処理の結果を目視で比較しやすくて感動しました。

NodeのUIに使っているReact Flowは知らなかったので勉強になりました。

AI主導でFastAPIのWebサービスを作るときに 人間が構造化すべき境界線

ちゃんと設計しないでAIに任せるとちぐはぐな実装をするから大事なところは取り決めておこうという話でした。データの意味・認証認可・画面ごとの整合性は人間が決めて、正しいかどうかを判断しようとのことでした。

Specは仕様書ではなく、AIと人間の間の約束事という考え方はこれからSpec駆動で開発する時に意識しようと思いました。

画面ごとの整合性がズレにきづく力は今の時代にどうつけていくのか考えて行きたいと思いました。*1

speakerdeck.com

Pydanticで複雑なJSONを一発でValidation

複雑で様々なバリエーションのあるJsonデータを安全に保存するためのバリデーションにJsonSchemaからPydanticに変えた話でした。 かなり整理されていたけれどもそれでも複雑でこれはきつい…というデータ構造だったので、機能が豊富で継承関係を整理しやすいPydanticにしたのは英断だと思いました。 JsonSchemaからPydanticのコードを生成するdatamodel-code-generatorは知らなかったので勉強になりました。*2

slides.takanory.net

DSPy入門 Pythonで実現する自動プロンプト最適化 〜人手によるプロンプト調整からの卒業

LLMのモデルの更新頻度高いしその都度プロンプトを書き換えないといけない作業は不毛だな…と思うので、それを自動化する話は興味深かったです。 機械学習よりも集めないといけないデータの件数が少ないとはいえ100件データを集めるのが難しいサービスもありそうと思う反面、データが集まっていて「こういうふうに回答すべき」というノウハウやドキュメントが存在するであろう問い合わせ系のサービスでは導入しやすそうと雑に考えました。

speakerdeck.com

キーノートとLTはスタッフ業しててちゃんと聴けずでした。X実況やスライドで追います。

懇親会

今年の懇親会は静岡市の醸造所 West Coast BrewingのStarwatcherの樽が用意されました。 スポンサーの皆様のお力と、会場から醸造所まで車で30分もかからない立地の良さと、車を運転してくれるスタッフのおかげで実現できたんだなあと感動しました。

スタッフ業

準備期間の大きな仕事としては2つありました。それと、当日スタッフをしました。

グルメマップ

去年と同じくランチは会場を閉めて食べに行ってもらうスタイルなのですが、去年は「どこに行けば良いか分からない」という声がありました。去年の反省から作りたいと思っていたので、グルメマップの企画・制作をしました。 Pythonで地図表示をするアプリを作る選択肢を考えつつも、費用・納期・要件の簡潔さからGoogle Mapで制作しました。

Xでオススメしたお店・メニューをランチで食べた報告を見て嬉しかったです!

www.google.com

ノベルティのステッカー

デザイン・サイズの決定、発注先選定、発注作業をしました。

デザインはロゴがすでにあったのでそちらを使用させていただきました。ノベルティの話がある前からロゴは存在していたのですが、ロゴの利用規約的にこういったグッズ制作に利用できることが分かっていたのはスムーズに進める上でありがたかったです。

ただ、見積もってみると発注してから出荷する期間が思ったより長く、「ノベルティ作ろう!」と決まったのが遅かったのもあり、試作することも考えると期間がギリギリなのは焦りました。バッファ込みでスケジュールを組みましたが、余裕でバッファ使いきりました。配布する分が届いたので安心しました。バッファはとても大切。

ノベルティのステッカー

当日スタッフ

受付・懇親会の用意をしました。タイムキーパーなどは他の方が担当してくれたので、トークをじっくり聞くことができました。 Connpassのサブイベント機能について、メインイベントを登録するとサブイベントの出席も確認できたのは便利で感動しました。 スタッフ業とは直接関係ないですが、Connpassを改善されたLTもあり、日々の進化・運用に感謝の気持ちが募りました。

speakerdeck.com

まとめ

今回始めてお会いした方、12月のPyladiesから知り合った方、数年ぶりにお会いした方、いろんなご縁がありました。 仕事でPythonを使わなくなりましたが、Pythonコミュニティは良いなと改めて実感しました。

*1:1回0→1で設計〜運用するのを体験するとか、E2Eテストやって気づきを得るなど泥臭い方法しか思いつかない… これからは、全体の整合性を保つための観点のガイドライン的なものをAIに読み込ませて、AIとの対話を通して学ぶとかになるのでしょうか。

*2:手放しに完璧に置き換えたからそのまま使える!というものでもなく十分な検証は必要とのことでした。が、生成AIにやらせると余分な項目追加されたりするので、単純作業はツール派の私は歓喜です!

「「分かった!」と思わせる説明の技術」を読んで

わわわIT辞典の方が書いた説明の技術の本だと聞いて読み始めました。わわわIT辞典は大変わかりやすい説明で、プログラミング初学者の頃によくお世話になっていました。数年が経ち今、仕事上説明をする機会が増え、分かりやすい説明ができる「わわわ」の方の考えを学ぼうと思いました。

https://amzn.asia/d/1Hyq6qg

説明はおもてなし

「分かった!」と思わせるためには、おもてなしとして説明をするとのことです。相手に「分かった」と思ってスッキリしてもらうこと。そのためにはまず相手のレベルを知って、相手のレベルに合わせた説明をします。

相手のレベルを知るために、「何%理解した?」と聞き、本人の自認よりも10-20%下げて理解度を見積もるのは良い考えだなと思いました。ダニングクルーガー効果で高く自認するケースもありますし、「こんなん分かる舐めるな」と言われた方が理解されないよりマシという吹っ切れた考え方も説明する時に活かそうと思いました。

思い切って削る

難しいことは思い切って削るのが「分かった」と思わせるコツだそうです。削ると専門家からみたら「正しくない」状態になるときがありますが、相手のレベルやコミュニーケーションの目的に沿って削るのは悪いことではないというスタンスです。難しいことは100%正確な状態だと難しいままで理解されないので、確かにと思いました。

いわるく「厳密には正しくない」ことを伝えるのは良くないとエンジニアだけの世界にいると思いがちになるので、コミュニーケーションの目的達成のためには悪いことではないというスタンスには救われました。

クライアントだけでなく、初学者に教える時もどこまで端折るかよく迷います。初学者のようにいずれは100%知らないといけない人については、レベルが足りなかろうが伝わらないと話が進まないところは説明を頑張りつつ、それ以外のところについてはその時のレベルに合わせ分解して説明して、そのうち100%を目指すと割り切るのも1つの戦略かもしれないと思いました。

「ITエンジニアの転職学」を読んで

直近で転職する予定はありませんが、現職に残るにしてもキャリア形成に有益だと評判が良いので読んでみました。

https://amzn.asia/d/cFxS4CJ

データや経験に基づいたアドバイスや理論に納得したのはもちろんのこと、筆者の方の温かい目線と書き味に、自然と前向きな気持ちになれました。

「XXしないとヤバい」「XXするのが一流」みたいな構文がなく、最後まで安心して読めました。キャリアは気になるけど過剰な煽りが苦手な人にもおすすめです。

また、「人生の一部としての仕事」というスタンスを感じました。例えば、「40代は人生の中でこういう時期だと心理学上言われているので、キャリアと向き合うときにこう感じる人もいるでしょう」と言った感じです。より良い人生にするためにこう向き合うと良いという、温かいメッセージを受け取りました。

6つの評価軸×5つのレベル

実装力、組織貢献力、事業貢献力などの6つの軸と

主力メンバーレベル、リーダーレベルなどの5つのレベル

を定義したマトリックス表が大変参考になりました。

いろんな会社の評価指標を参考にされており、具体的な内容に差はあれど方向性は大体他の会社もそんな感じなんだろうな、と私も数社経験したなりに思いました。

各軸での自分のレベルを振り返り、どんな経験を積めば次のレベルに到達できそうか考えるきっかけになりました。

評価制度を考えている人や、マネジメント業務をしている人にも役に立ちそうです。

20,30,40,50代以降の過ごし方

どの年代がどんなことを期待されているのか、どんな風にキャリアを考えるのかが述べられていました。

こちらも、自分の立ち位置の振り返りとマネジメント業務両方に役立ちそうです。

30代の仕事の向き合い方として「組織の目標を達成することにフォーカスしつつ、その過程に自分独自の工夫を加えて、会社と自分のこだわりのバランスを取る」というところが印象的でした。(これはチームリードしているなら、20代でも当てはまること)

自分の工夫を加えて目標達成した結果が、「〇〇さんがいないとできなかったこと」になるのかもしれないと思いました。いきないそこを目指すのは難しいけど、自分の工夫を加えるのはそれよりはハードルが低いので、そのスタンスで頑張ろうと思いました。

django-anymailとResendでメール送信する 〜Railway無料プランSMTP通信できない問題の解決〜

RailwayというPaaSのFreeプランで開発をすすめていたところ、メール送信でつまづいたのでその原因と解決策の共有です。

使用技術

原因

RailwayはProプラン以上でないとSMTP通信できないそうです。 Outbound Networking | Railway Docs

何回メールを送ってもSTG環境では500エラーになり、ローカル環境では正常送れるのはこの仕様のためでした。

HTTP APIを使ってメールを送信しないといけません。

解決策

今回は運良くDjangoを使っていたので助かりました。

結論から書くと、django-anymailというDjangoでメール送信を簡単に実現するパッケージを使い、ResendのHTTP API通信のメール送信機能を使ってメール送信します。

settings.pyにこれを追加するだけ!

EMAIL_BACKEND = "anymail.backends.resend.EmailBackend"  # デフォルト値から書き換え
ANYMAIL = {
    "RESEND_API_KEY": os.environ.get('RESEND_API_KEY'),
}  # 追加

まず、以下の条件でメールサービスを探しました。

  • [must] HTTP API通信でメール送信できる
  • [want] 無料プランがある
  • [want] django-anymailがサポートしているメールサービスである

3条件すべて揃っているのがResend でした。 なお、SendGridも候補にあがっていましたが、2025年5月にdjango-anymailのサポート切れとなっていました。

github.com

SendGridのパッケージを使えばSendGridを使えますが、django-anymailはsettings.pyに設定値をいれるだけでメールサービスと通信する箇所を実装しなくてもメール送信できる手軽さがあります。 手軽さが勝利して、django-anymailを使えるResendを選びました。

まとめ

  • django-anymailを使えばsettings.pyを書き換えるだけでメールサービスを利用できる
  • django-anymailがサポートしているメールサービスを選ぶ必要がある
  • Resendは無料プランがある かつ django-anymailのサポートがあるのでDjangoでの開発の最初に使うメールサービスとしておすすめ