Skip to content

React Email

React Email 是一个库,允许您使用 React 组件创建电子邮件。

由于 Elysia 使用 Bun 作为运行环境,我们可以直接编写一个 React Email 组件,并将 JSX 直接导入到我们的代码中以发送电子邮件。

安装

要安装 React Email,请运行以下命令:

bash
bun add -d react-email
bun add @react-email/components react react-dom

然后在 package.json 中添加以下脚本:

json
{
  "scripts": {
    "email": "email dev --dir src/emails"
  }
}

我们建议将电子邮件模板添加到 src/emails 目录中,因为我们可以直接导入 JSX 文件。

TypeScript

如果您使用 TypeScript,可能需要在 tsconfig.json 中添加以下内容:

json
{
  "compilerOptions": {
	"jsx": "react"
  }
}

您的第一封电子邮件

创建文件 src/emails/otp.tsx,并输入以下代码:

tsx
import * as React from 'react'
import { Tailwind, Section, Text } from '@react-email/components'

export default function OTPEmail({ otp }: { otp: number }) {
    return (
        <Tailwind>
            <Section className="flex justify-center items-center w-full min-h-screen font-sans">
                <Section className="flex flex-col items-center w-76 rounded-2xl px-6 py-1 bg-gray-50">
                    <Text className="text-xs font-medium text-violet-500">
                        验证您的电子邮件地址
                    </Text>
                    <Text className="text-gray-500 my-0">
                        使用以下代码验证您的电子邮件地址
                    </Text>
                    <Text className="text-5xl font-bold pt-2">{otp}</Text>
                    <Text className="text-gray-400 font-light text-xs pb-4">
                        此代码在 10 分钟内有效
                    </Text>
                    <Text className="text-gray-600 text-xs">
                        感谢加入我们
                    </Text>
                </Section>
            </Section>
        </Tailwind>
    )
}

OTPEmail.PreviewProps = {
    otp: 123456
}

您可能会注意到我们使用了 @react-email/components 来创建电子邮件模板。

该库提供了一组与邮件客户端(例如 Gmail、Outlook 等)兼容的组件,包括 使用 Tailwind 进行样式设置

我们还向 OTPEmail 函数添加了 PreviewProps。这仅在我们在 PLAYGROUND 上预览电子邮件时适用。

预览您的电子邮件

要预览您的电子邮件,请运行以下命令:

bash
bun email

这将打开一个浏览器窗口,显示您的电子邮件预览。

React Email playground showing an OTP email we have just written

发送电子邮件

要发送电子邮件,我们可以使用 react-dom/server 来渲染电子邮件,然后使用首选提供商进行发送:

tsx
import { Elysia, t } from 'elysia'

import * as React from 'react'
import { renderToStaticMarkup } from 'react-dom/server'

import OTPEmail from './emails/otp'

import nodemailer from 'nodemailer'

const transporter = nodemailer.createTransport({ 
  	host: 'smtp.gehenna.sh', 
  	port: 465, 
  	auth: { 
  		user: 'makoto', 
  		pass: '12345678'
  	} 
}) 

new Elysia()
	.get('/otp', async ({ body }) => {
		// 随机生成 100,000 到 999,999 之间的数字
  		const otp = ~~(Math.random() * (900_000 - 1)) + 100_000

		const html = renderToStaticMarkup(<OTPEmail otp={otp} />)

        await transporter.sendMail({ 
        	from: 'ibuki@gehenna.sh', 
           	to: body, 
           	subject: '验证您的电子邮件地址', 
            html, 
        }) 

        return { success: true }
	}, {
		body: t.String({ format: 'email' })
	})
	.listen(3000)
tsx
import { Elysia, t } from 'elysia'

import OTPEmail from './emails/otp'

import Resend from 'resend'

const resend = new Resend('re_123456789') 

new Elysia()
	.get('/otp', async ({ body }) => {
		// 随机生成 100,000 到 999,999 之间的数字
  		const otp = ~~(Math.random() * (900_000 - 1)) + 100_000

        await resend.emails.send({ 
        	from: 'ibuki@gehenna.sh', 
           	to: body, 
           	subject: '验证您的电子邮件地址', 
            html: <OTPEmail otp={otp} />, 
        }) 

        return { success: true }
	}, {
		body: t.String({ format: 'email' })
	})
	.listen(3000)
tsx
import { Elysia, t } from 'elysia'

import * as React from 'react'
import { renderToStaticMarkup } from 'react-dom/server'

import OTPEmail from './emails/otp'

import { type SendEmailCommandInput, SES } from '@aws-sdk/client-ses'
import { fromEnv } from '@aws-sdk/credential-providers'

const ses = new SES({ 
    credentials: 
        process.env.NODE_ENV === 'production' ? fromEnv() : undefined
}) 

new Elysia()
	.get('/otp', async ({ body }) => {
		// 随机生成 100,000 到 999,999 之间的数字
  		const otp = ~~(Math.random() * (900_000 - 1)) + 100_000

		const html = renderToStaticMarkup(<OTPEmail otp={otp} />)

        await ses.sendEmail({ 
            Source: 'ibuki@gehenna.sh', 
            Destination: { 
                ToAddresses: [body] 
            }, 
            Message: { 
                Body: { 
                    Html: { 
                        Charset: 'UTF-8', 
                        Data: html 
                    } 
                }, 
                Subject: { 
                    Charset: 'UTF-8', 
                    Data: '验证您的电子邮件地址'
                } 
            } 
        } satisfies SendEmailCommandInput) 

        return { success: true }
	}, {
		body: t.String({ format: 'email' })
	})
	.listen(3000)
tsx
import { Elysia, t } from 'elysia'

import OTPEmail from './emails/otp'

import sendgrid from "@sendgrid/mail"

sendgrid.setApiKey(process.env.SENDGRID_API_KEY) 

new Elysia()
	.get('/otp', async ({ body }) => {
		// 随机生成 100,000 到 999,999 之间的数字
  		const otp = ~~(Math.random() * (900_000 - 1)) + 100_000

    	const html = renderToStaticMarkup(<OTPEmail otp={otp} />)

        await sendgrid.send({ 
        	from: 'ibuki@gehenna.sh', 
           	to: body, 
           	subject: '验证您的电子邮件地址', 
            html 
        }) 

        return { success: true }
	}, {
		body: t.String({ format: 'email' })
	})
	.listen(3000)

TIP

注意,我们可以直接导入电子邮件组件,这要归功于 Bun

您可以在 React Email Integration 中查看所有可用的 React Email 集成,并在 React Email documentation 中了解更多信息。