Use Cases

Claude Codeでメール送信機能を効率的に実装する方法

Claude Codeを使ってトランザクションメール、テンプレート管理、メールキューの実装を効率化する方法を解説します。

メール機能の実装にClaude Codeを使うメリット

メール送信機能は、テンプレートの作成、送信ロジック、エラーハンドリング、リトライ処理など考慮点が多い機能です。Claude Codeはこれらを一括して実装し、テスト可能な構成を提案してくれます。

Resendによるメール送信の基本

> Resendを使ったメール送信サービスを作成して。
> React Emailでテンプレートを管理して。
> リトライ処理とエラーハンドリングも実装して。
// src/services/email-service.ts
import { Resend } from 'resend';

const resend = new Resend(process.env.RESEND_API_KEY);

interface SendEmailOptions {
  to: string | string[];
  subject: string;
  html: string;
  text?: string;
  replyTo?: string;
}

export class EmailService {
  private maxRetries = 3;

  async send(options: SendEmailOptions): Promise<{ id: string }> {
    let lastError: Error | null = null;

    for (let attempt = 1; attempt <= this.maxRetries; attempt++) {
      try {
        const { data, error } = await resend.emails.send({
          from: 'MyApp <[email protected]>',
          to: options.to,
          subject: options.subject,
          html: options.html,
          text: options.text,
          replyTo: options.replyTo,
        });

        if (error) throw new Error(error.message);
        return { id: data!.id };
      } catch (err) {
        lastError = err as Error;
        if (attempt < this.maxRetries) {
          await this.delay(1000 * attempt); // 指数バックオフ
        }
      }
    }

    throw new Error(`Failed after ${this.maxRetries} attempts: ${lastError?.message}`);
  }

  private delay(ms: number) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }
}

React Emailでテンプレート作成

// emails/welcome.tsx
import {
  Body,
  Container,
  Head,
  Heading,
  Html,
  Link,
  Preview,
  Section,
  Text,
} from '@react-email/components';

interface WelcomeEmailProps {
  userName: string;
  loginUrl: string;
}

export function WelcomeEmail({ userName, loginUrl }: WelcomeEmailProps) {
  return (
    <Html>
      <Head />
      <Preview>{userName}さん、ようこそ!</Preview>
      <Body style={{ backgroundColor: '#f6f9fc', fontFamily: 'sans-serif' }}>
        <Container style={{ margin: '0 auto', padding: '40px 20px', maxWidth: '560px' }}>
          <Heading style={{ fontSize: '24px', color: '#333' }}>
            ようこそ、{userName}さん!
          </Heading>
          <Text style={{ fontSize: '16px', color: '#555', lineHeight: '1.6' }}>
            アカウントが正常に作成されました。以下のリンクからログインしてサービスをご利用ください。
          </Text>
          <Section style={{ textAlign: 'center', margin: '32px 0' }}>
            <Link
              href={loginUrl}
              style={{
                backgroundColor: '#2563eb',
                color: '#fff',
                padding: '12px 24px',
                borderRadius: '6px',
                textDecoration: 'none',
                fontSize: '16px',
              }}
            >
              ログインする
            </Link>
          </Section>
          <Text style={{ fontSize: '14px', color: '#888' }}>
            ご不明な点がございましたらお気軽にお問い合わせください。
          </Text>
        </Container>
      </Body>
    </Html>
  );
}

メール送信の統合

// src/services/notification-service.ts
import { render } from '@react-email/render';
import { EmailService } from './email-service';
import { WelcomeEmail } from '../emails/welcome';

const emailService = new EmailService();

export class NotificationService {
  async sendWelcomeEmail(user: { email: string; name: string }) {
    const html = await render(
      WelcomeEmail({
        userName: user.name,
        loginUrl: `${process.env.APP_URL}/login`,
      })
    );

    return emailService.send({
      to: user.email,
      subject: `ようこそ、${user.name}さん!`,
      html,
    });
  }

  async sendPasswordReset(email: string, token: string) {
    const resetUrl = `${process.env.APP_URL}/reset-password?token=${token}`;
    const html = await render(
      PasswordResetEmail({ resetUrl })
    );

    return emailService.send({
      to: email,
      subject: 'パスワードリセットのご案内',
      html,
    });
  }
}

メールキューの実装

大量のメール送信にはキューを使います。

// src/queues/email-queue.ts
import { Queue, Worker } from 'bullmq';
import { EmailService } from '../services/email-service';

const emailQueue = new Queue('emails', {
  connection: { host: 'localhost', port: 6379 },
});

// メールをキューに追加
export async function enqueueEmail(options: {
  to: string;
  subject: string;
  html: string;
}) {
  await emailQueue.add('send-email', options, {
    attempts: 3,
    backoff: { type: 'exponential', delay: 2000 },
    removeOnComplete: 100,
    removeOnFail: 50,
  });
}

// ワーカーで処理
const emailService = new EmailService();

new Worker('emails', async (job) => {
  await emailService.send(job.data);
  console.log(`Email sent: ${job.data.to}`);
}, {
  connection: { host: 'localhost', port: 6379 },
  concurrency: 5,
});

テストの実装

import { vi, describe, it, expect } from 'vitest';
import { NotificationService } from './notification-service';

vi.mock('resend', () => ({
  Resend: vi.fn().mockImplementation(() => ({
    emails: {
      send: vi.fn().mockResolvedValue({ data: { id: 'test-id' }, error: null }),
    },
  })),
}));

describe('NotificationService', () => {
  it('should send welcome email', async () => {
    const service = new NotificationService();
    const result = await service.sendWelcomeEmail({
      email: '[email protected]',
      name: 'テストユーザー',
    });
    expect(result.id).toBe('test-id');
  });
});

まとめ

Claude Codeを使えば、メール送信機能をテンプレート管理からキュー処理まで一括して実装できます。特にReact Emailによるテンプレート作成は、Claude Codeが得意とする分野です。メール機能の設計方針をCLAUDE.mdに記述しておくと、一貫した実装が得られます。テスト駆動で開発を進めるコツはリファクタリング自動化の記事も参考にしてください。

Claude Codeの詳細はAnthropic公式ドキュメントをご覧ください。React Emailの詳細はReact Email公式サイトを参照してください。

#Claude Code #メール #SendGrid #Resend #Node.js