0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[FastAPI] SESを使用し、ユーザー招待メールを送信し、ユーザー登録を成功させよう!!

Posted at

はじめに

本記事では、FastAPIを使用して、PostgreSQLにユーザー情報を保存し、**AWS SES(Simple Email Service)**を利用して招待メールを送信するシステムを構築する方法を解説します。システム設計から実装までを丁寧に説明し、初心者にも理解できるように構成しています。

必要な環境の準備

使用する技術スタック 説明
FastAPI Pythonで書かれたWebフレームワーク。非同期処理に強く、軽量で高性能。
PostgreSQL 信頼性の高いオープンソースのリレーショナルデータベース。
AWS SES メール送信サービス。大規模なメール送信に対応。

必要なパッケージ

まず、必要なパッケージをインストールします。

pip install fastapi uvicorn psycopg2 sqlalchemy boto3
使用する技術スタック 説明
FastAPI APIの作成に使用。
uvicorn ASGIサーバー。FastAPIを起動するために必要。
psycopg2 PostgreSQLとPythonを接続するためのライブラリ。
SQLAlchemy ORM(Object Relational Mapper)としてデータベースとやり取り。
boto3 AWSサービス(SES)を操作するためのライブラリ。

PostgreSQLのセットアップ

PostgreSQLは事前にインストールしておく必要があります。以下のコマンドでデータベースを作成します。

CREATE DATABASE user_registration;

データベース設計(PostgreSQL)

ユーザー情報招待トークンを管理するために、2つのテーブルを設計します。

ユーザーテーブル(users)

カラム名 データ型 説明
id INTEGER ユーザーの一意のID(主キー)。
email VARCHAR(255) ユーザーのメールアドレス(ユニーク)。
name VARCHAR(255) ユーザー名。
is_active BOOLEAN アクティブかどうかを示すフラグ(招待を受けた後に有効化)。
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    email VARCHAR(255) UNIQUE NOT NULL,
    name VARCHAR(255),
    is_active BOOLEAN DEFAULT FALSE
);

招待トークンテーブル(invitation_tokens)

カラム名 データ型 説明
id INTEGER トークンの一意のID(主キー)。
email VARCHAR(255) 招待されたメールアドレス。
token VARCHAR(255) 招待トークン。
is_used BOOLEAN トークンが使用済みかどうかを示すフラグ。
CREATE TABLE invitation_tokens (
    id SERIAL PRIMARY KEY,
    email VARCHAR(255) NOT NULL,
    token VARCHAR(255) NOT NULL,
    is_used BOOLEAN DEFAULT FALSE
);

データベース接続設定

まずはSQLAlchemyを使ってデータベース接続を設定します。

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, declarative_base

DATABASE_URL = "postgresql://user:password@localhost/user_registration"

engine = create_engine(DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()

ユーザーモデルとトークンモデル

SQLAlchemyでテーブルモデルを定義します。

from sqlalchemy import Column, Integer, String, Boolean

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True, index=True)
    email = Column(String, unique=True, index=True)
    name = Column(String)
    is_active = Column(Boolean, default=False)

class InvitationToken(Base):
    __tablename__ = 'invitation_tokens'
    id = Column(Integer, primary_key=True, index=True)
    email = Column(String)
    token = Column(String)
    is_used = Column(Boolean, default=False)

FastAPIのルート設計

APIは以下の2つに分離します。

  1. 招待メール送信API: ユーザーのメールアドレスを受け取り、AWS SESを使って招待メールを送信する
  2. ユーザー登録API: 招待メールのリンクに含まれるトークンを使い、ユーザー登録を完了する

招待メール送信と新規ユーザー登録の流れ

1. 招待メール送信の流れ

このセクションでは、フロントエンドからユーザーのメールアドレスを送信し、バックエンドで処理して招待メールを送信する流れを説明します。

Step 1: フロントエンドからリクエストを送信

  • フロントエンド(例:ReactやVue.jsなどのクライアントアプリケーション)で、ユーザーのメールアドレスを収集し、APIエンドポイント/inviteにPOSTリクエストとして送信します。
  • このリクエストには、ユーザーのメールアドレスが含まれます。

Step 2: FastAPIサーバーでトークン生成と保存

  • サーバー側で、FastAPIはこのリクエストを受け取ります。
  • FastAPIのエンドポイント/inviteは、受け取ったメールアドレスに基づいて新しい招待トークンを生成します。トークンは通常、UUID形式を使用して一意の値を生成します。
    • 例: token = str(uuid.uuid4())
  • このトークンとメールアドレスをinvitation_tokensテーブルに保存します。保存されるデータには、以下の情報が含まれます:
    • メールアドレス
    • 招待トークン
    • トークンの使用ステータス(is_used=False

Step 3: AWS SESでメール送信

  • トークンが生成され、データベースに保存されたら、次にAWS SES(Simple Email Service)を使用して、ユーザーに招待メールを送信します。
  • メールには、トークンを含んだリンクが記載されており、ユーザーがそのリンクをクリックすると登録画面に誘導されます。
    • 例: https://example.com/register?token=<generated_token>
  • AWS SESは、Boto3ライブラリを通じてメールを送信します。

2. 新規ユーザー登録の流れ

招待を受け取ったユーザーが、登録を完了する流れです。

Step 1: 招待メールを受け取ったユーザーがリンクをクリック

  • ユーザーは、送られた招待メール内のリンクをクリックします。このリンクには、トークンがクエリパラメータとして含まれています。
    • 例: https://example.com/register?token=<generated_token>

Step 2: トークンを持ってAPIエンドポイントにリクエストを送信

  • ユーザーは、登録画面で名前やパスワードなどの必要情報を入力し、登録リクエストをバックエンドの/registerエンドポイントに送信します。このリクエストには、招待トークンも含まれています。

Step 3: FastAPIでトークンを検証

  • サーバー側では、受け取ったトークンをデータベース(invitation_tokensテーブル)で確認します。
  • トークンが存在し、かつ未使用であることを確認します(is_used=False)。
  • トークンが有効な場合、usersテーブルにユーザー情報を保存し、ユーザー登録を完了します。
  • 登録完了後、該当のトークンを使用済み(is_used=True)に更新します。

このセクションのまとめ

招待メール送信の流れ

  1. フロントエンドからユーザーのメールアドレスをAPIに送信。
  2. FastAPIで招待トークンを生成し、データベースに保存。
  3. AWS SESを使ってユーザーに招待メールを送信。

新規ユーザー登録の流れ

  1. ユーザーがメール内のリンクをクリック。
  2. トークンを使用してFastAPIにリクエストを送信。
  3. FastAPIでトークンを検証し、ユーザーを登録。トークンを使用済みにする。

このようにFastAPIとPostgreSQL、SESを使ったシンプルかつセキュアなユーザー招待と登録システムが構築できます。

AWS SESを用いたメール送信

AWS SESの設定はAWSコンソール上で行います。SESを使用するためには、ドメインの検証やメールアドレスの確認が必要です。
boto3を使ってSESにメールを送信する関数を実装します。

コード例(FastAPIエンドポイント /invite の処理):

from fastapi import FastAPI, HTTPException, Depends
from sqlalchemy.orm import Session
from models import InvitationToken
import uuid
import boto3

app = FastAPI()

# データベースセッションの依存関係
def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()


# SESの設定
ses = boto3.client('ses', region_name='us-west-2')

@app.post("/invite")
def send_invitation(email: str, db: Session = Depends(get_db)):
    # トークンの生成
    token = str(uuid.uuid4())

    # データベースに保存
    invitation_token = InvitationToken(email=email, token=token, is_used=False)
    db.add(invitation_token)
    db.commit()

    # 招待メールの送信
    send_email_with_ses(email, token)

    return {"message": "Invitation sent"}

def send_email_with_ses(email, token):
    # メールの内容を構築
    response = ses.send_email(
        Source='your-email@example.com',
        Destination={'ToAddresses': [email]},
        Message={
            'Subject': {'Data': 'You are invited to register'},
            'Body': {
                'Text': {
                    'Data': f"Click the link to register: https://example.com/register?token={token}"
                }
            }
        }
    )
    return response

この関数はSESを使って指定したメールアドレスに招待メールを送信します。


ユーザー登録API

コード例(FastAPIエンドポイント /register の処理):

from fastapi import FastAPI, HTTPException, Depends
from sqlalchemy.orm import Session
from models import User, InvitationToken
from database import get_db

@app.post("/register")
def register_user(name: str, email: str, token: str, db: Session = Depends(get_db)):
    # トークンの検証
    invitation_token = db.query(InvitationToken).filter(InvitationToken.token == token).first()

    if not invitation_token or invitation_token.is_used:
        raise HTTPException(status_code=400, detail="Invalid or used token")

    # ユーザーの作成
    new_user = User(name=name, email=email, is_active=True)
    db.add(new_user)
    db.commit()

    # トークンを使用済みに更新
    invitation_token.is_used = True
    db.commit()

    return {"message": "User registered successfully"}

まとめ

この記事では、FastAPI、PostgreSQL、AWS SESを使用して、ユーザー招待メールを送信し、ユーザーを登録するAPIの構築方法を解説しました。API設計を分かりやすくするため、機能ごとに分離して説明し、SESを用いたメール送信も丁寧に解説しました。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?