Ross
Ross•11mo ago

resend problems

How can I use resend with CONVEX, someone help me please. I am struggling with that for about 3 HOURS HAHAHA starting to get crazy
5 Replies
lee
lee•11mo ago
if you have specific questions, i recommend making a #support-community thread. I also recommend the ai chatbot on docs.convex.dev and search.convex.dev ( for example, maybe this will help https://discord.com/channels/1019350475847499849/1209891383310295050/1209898314690990150 )
Ross
RossOP•11mo ago
heey someone know how to implement: convex -> nextjs (app router) api -> resend ?
oferitz
oferitz•11mo ago
This is how I've implemented it, and it's probably not the best/efficient/clean way to do it, since you need to "curry" the JWT token all the way from the frontend through convex action to your Next.js API endpoint. This solution is only relevant if your trigger to send an email starts from a frontend action. For my use case, this is what I needed, and it is working. So here it goes: When you want to trigger your action, you need to grab the JWT token (I'm using Clerk, but there should be an equivalent hook for any other provider as well):
import { useAuth } from '@clerk/nextjs'
const { getToken } = useAuth()
const yourConvexAction = useAction(api.actions.yourConvexAction)

const doSomeAction = async () => {
const token = await getToken()
await yourConvexAction({ ...otherParams, token })
}
import { useAuth } from '@clerk/nextjs'
const { getToken } = useAuth()
const yourConvexAction = useAction(api.actions.yourConvexAction)

const doSomeAction = async () => {
const token = await getToken()
await yourConvexAction({ ...otherParams, token })
}
2. In your Convex action:
export const yourConvexAction = action({
args: {
// other params ...
token: v.union(v.string(), v.null())
},
handler: async (
{runAction },
{ token }
) => {

// do some logic and fetch some data for the email

await runAction(internal.email.sendEmailToUser, {
subject: 'Your email subject,
from: 'from',
to: 'user.email',
data: {
// data inside the email body
},
token
})
}
})
export const yourConvexAction = action({
args: {
// other params ...
token: v.union(v.string(), v.null())
},
handler: async (
{runAction },
{ token }
) => {

// do some logic and fetch some data for the email

await runAction(internal.email.sendEmailToUser, {
subject: 'Your email subject,
from: 'from',
to: 'user.email',
data: {
// data inside the email body
},
token
})
}
})
3. The internal action:
export const sendEmailToUser = internalAction({
args: {
from: v.string(),
to: v.string(),
subject: v.string(),
data: v.any(),
token: v.string()
},
handler: async (_, payload) => {
try {
const res = await fetch('https://your-nextjs-app-domain/api/sendEmail', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${payload.token}`
},
body: JSON.stringify(payload)
})
const json = await res.json()
return json
} catch (error: any) {
console.error('Error sending email', error?.message)
return false
}
}
})
export const sendEmailToUser = internalAction({
args: {
from: v.string(),
to: v.string(),
subject: v.string(),
data: v.any(),
token: v.string()
},
handler: async (_, payload) => {
try {
const res = await fetch('https://your-nextjs-app-domain/api/sendEmail', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${payload.token}`
},
body: JSON.stringify(payload)
})
const json = await res.json()
return json
} catch (error: any) {
console.error('Error sending email', error?.message)
return false
}
}
})
4. and finally the Next.js API route:
import { Resend } from 'resend'
import jwt from 'jsonwebtoken'
import { YourEmailTemplate } from '~/emails/YourEmailTemplate'
import type React from 'react'
import { NextResponse } from 'next/server'


export const dynamic = 'force-dynamic'
export const revalidate = 0
export async function POST(req: Request) {
const publicKey = process.env.CLERK_JWT_PK as string
const resend = new Resend(process.env.RESEND_API_KEY)
const bearerToken = req.headers.get('Authorization')
if (bearerToken === undefined) {
return NextResponse.json(
{
error: 'Not signed in'
},
{
status: 401
}
)
}
try {
if (bearerToken) {
const token = bearerToken.split(' ')[1]
jwt.verify(token, publicKey)
const body = await req.json()
const { from, to, subject, data } = body
const emailResponse = await resend.emails.send({
from,
to,
subject,
react: <YourEmailTemplate data={data} />
})
return NextResponse.json(
{
...emailResponse
},
{
status: 200
}
)
}
} catch (error) {
return NextResponse.json(
{
error: 'Not signed in'
},
{
status: 400
}
)
}
}
import { Resend } from 'resend'
import jwt from 'jsonwebtoken'
import { YourEmailTemplate } from '~/emails/YourEmailTemplate'
import type React from 'react'
import { NextResponse } from 'next/server'


export const dynamic = 'force-dynamic'
export const revalidate = 0
export async function POST(req: Request) {
const publicKey = process.env.CLERK_JWT_PK as string
const resend = new Resend(process.env.RESEND_API_KEY)
const bearerToken = req.headers.get('Authorization')
if (bearerToken === undefined) {
return NextResponse.json(
{
error: 'Not signed in'
},
{
status: 401
}
)
}
try {
if (bearerToken) {
const token = bearerToken.split(' ')[1]
jwt.verify(token, publicKey)
const body = await req.json()
const { from, to, subject, data } = body
const emailResponse = await resend.emails.send({
from,
to,
subject,
react: <YourEmailTemplate data={data} />
})
return NextResponse.json(
{
...emailResponse
},
{
status: 200
}
)
}
} catch (error) {
return NextResponse.json(
{
error: 'Not signed in'
},
{
status: 400
}
)
}
}
Michal Srb
Michal Srb•11mo ago
In general, you do not need Next.js API routes when you have Convex. For Resend, you don't even need HTTP Actions, just send the email from an action using the Resend TypeScript API, like this: https://github.com/xixixao/saas-starter/blob/main/convex/users/teams/members/invites.tsx#L135-L150 To use React add jsx: "react-jsx" to the convex/tsconfig.json and name your file with .tsx or .jsx
GitHub
saas-starter/convex/users/teams/members/invites.tsx at main · xixix...
Convex, Clerk, Next.js, Convex Ents. Contribute to xixixao/saas-starter development by creating an account on GitHub.
Ross
RossOP•11mo ago
thaaaaanks a lot man wow !! It'll help a lot! You are the Goat! 🤌😎

Did you find this page helpful?