#do you know well about latest resend component?
20 messages · Page 1 of 1 (latest)
Yes, I can provide information about the latest Resend component for Convex based on the provided knowledge sources.
The Resend Convex Component is the official way to integrate the Resend email service with your Convex project. It offers features such as:
- Queueing: You can send as many emails as you want, as fast as you want—they'll all be delivered eventually.
- Batching: Automatically batches large groups of emails and sends them to Resend efficiently.
- Durable execution: Uses Convex workpools to ensure emails are eventually delivered, even in the face of temporary failures or network outages.
- Idempotency: Manages Resend idempotency keys to guarantee emails are delivered exactly once, preventing accidental spamming from retries.
- Rate limiting: Honors API rate limits established by Resend.
To get started, you install the component with:
npm install @convex-dev/resend
You then configure it in your Convex app and can use it to send emails via a simple API. The component also supports advanced features like webhooks for email status updates, React Email for templating, and cron jobs for cleaning up old emails. By default, it runs in test mode, so you need to explicitly set testMode: false to send emails to real addresses. You can also handle email events, check status, and cancel emails if needed.
For more details and code examples, see the official documentation and example repo linked in the sources:
If you have specific questions about features or usage, feel free to ask!
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@fallow vigil Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Let me check the knowledge base for you again. One moment! :books:
The log message 'Email not found for resendId: ...' indicates that the Resend component received a webhook event for an email ID that it does not recognize in its internal database. This is a built-in behavior of the Resend Convex Component: when a webhook event arrives for an email that was not sent (or tracked) by the component, it logs this message and ignores the event.
Possible reasons for this:
-
The email was not sent using the Resend component in your Convex app.
The component only tracks emails that were sent using its ownsendEmailmethod. If the email referenced by the webhook was sent outside of Convex (e.g., directly via the Resend dashboard or another integration), the component will not have a record of it and will log this message. -
Test Mode is enabled.
In your code, you havetestMode: truein your Resend component configuration. In test mode, only emails sent to test addresses are actually processed, and other emails may not be tracked or stored. This could result in webhook events for emails that the component does not recognize, especially if you are testing with real addresses or the Resend dashboard. -
The webhook is firing for old or unrelated emails.
If you recently set up the webhook, Resend may send events for previous emails that were not sent via your current Convex deployment.
What you can do:
- Ensure all emails are sent via the Convex Resend component.
Only emails sent using the component'ssendEmailmethod will be tracked and recognized by the webhook handler.
-
Check your test mode setting.
If you want to process real emails, settestMode: falsein your Resend component configuration.export const resend: Resend = new Resend(components.resend, { testMode: false, onEmailEvent: internal.webhookEmail.handleResendEventWebhook, });See Resend component options for more details.
-
Ignore unrelated webhook events.
The component is designed to safely ignore events for unknown emails, so this log is informational and not an error.
This behavior and the log message are expected and documented as part of the Resend Convex Component's design for handling webhooks and email status events. If you want to see events processed, make sure to send emails through the component and use the correct mode and addresses Resend Convex Component.
If you need to debug further, you can check the example repo for a working setup and compare your configuration.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@fallow vigil Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Let me check the knowledge base for you again. One moment! :books:
Based on the knowledge sources, the Convex Resend component (@convex-dev/resend) is designed for general-purpose email sending and is not a drop-in replacement for the Auth.js provider configuration used in Convex Auth (@auth/core/providers/resend).
Convex Auth expects an Auth.js-compatible provider object for authentication flows (like magic links or OTPs). The Resend component, on the other hand, is a Convex Component for sending and tracking emails, not for handling authentication flows directly. The two are separate in their intended use:
- Convex Auth: Uses Auth.js provider configs (like your
CustomResendProvider) to handle authentication emails (magic links, OTPs, etc.) as part of the authentication process. This is required for theconvexAuthsetup inauth.tsand is documented in the Convex Auth setup guides (Magic Links, OTPs). - Resend Component: Used for sending transactional or notification emails from your Convex app, not for authentication flows. It is set up and used separately, as shown in the Resend Convex Component docs.
You cannot use the Resend Convex Component as a provider in your auth.ts for Convex Auth. You must continue to use an Auth.js provider (like your CustomResendProvider) for authentication-related emails.
If you want to customize the email content or use React components for your authentication emails, you can do so within the sendVerificationRequest function of your Auth.js provider, as you are already doing. For transactional emails outside of authentication, use the Resend Convex Component.
Summary:
- Use Auth.js providers for Convex Auth authentication flows.
- Use the Resend Convex Component for general email sending, not for authentication.
If you need more advanced templating for authentication emails, you can use React components in your Auth.js provider's sendVerificationRequest, as shown in the docs (Magic Links).
If you need more details or examples, let me know!
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@fallow vigil Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Let me check the knowledge base for you again. One moment! :books:
Yes, you are correct: to use React Email templates (i.e., render JSX to HTML for emails), you must use a Convex Node action with the "use node" directive. This is because React Email and its dependencies require Node.js APIs that are only available in the Node runtime, not in the default Convex runtime (Using React Email).
WARNING: React Email requires some Node dependencies thus it must run in a Convex Node action and not a regular Action.
Regarding internal functions in "use node" files:
You are also correct that you cannot declare internal functions (like internalMutation or internalAction) in files with "use node". The Node.js runtime in Convex is restricted to action functions only. Internal functions, queries, and mutations must be defined in files without the "use node" directive (Node.js runtime).
Files with the
"use node"directive should not contain any Convex queries or mutations since they cannot be run in the Node.js runtime.
So, if you want to listen for webhook events (which typically use internalMutation), you must define those internal functions in a separate file without "use node". You can then call those internal functions from your Node action if needed, but you cannot define them in the same "use node" file.
Summary:
- Use
"use node"for actions that need Node.js APIs (like React Email rendering). - Define internal functions (for webhooks, etc.) in regular files, not in
"use node"files.
This is a current limitation of Convex's function system (Node.js runtime).
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@fallow vigil Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@hasty thorn
import { vEmailEvent, vEmailId } from '@convex-dev/resend';
import { internalMutation } from './_generated/server';
import { sendDiscordNotification } from '../utils/discordwebhook';
const DISCORD_WEBHOOK_URL = process.env.DISCORD_WEBHOOK_URL || '';
export const handleResendEventWebhook = internalMutation({
args: {
id: vEmailId,
event: vEmailEvent,
},
handler: async (ctx, args) => {
const { id, event } = args;
console.log('Email event received:', { id, event }, '\n\n');
// Extract email data for logging
const emailData = {
to: event.data.to,
from: event.data.from,
subject: event.data.subject,
created_at: event.data.created_at,
...(event.data.cc && { cc: event.data.cc }),
...(event.data.bcc && { bcc: event.data.bcc }),
...(event.data.reply_to && { reply_to: event.data.reply_to }),
...(event.data.broadcast_id && {
broadcast_id: event.data.broadcast_id,
}),
...(event.data.tags && { tags: event.data.tags }),
};
// Log all events for monitoring
console.log('Email event received:', {
id,
event: { ...event, data: emailData },
});
switch (event.type) {
case 'email.failed':
console.error('Email delivery failed permanently:', id);
await sendDiscordNotification(
DISCORD_WEBHOOK_URL,
event,
id,
'error'
);
break;
sendDiscordNotification function is using fetch ... so can you make it able to call from internalMutation?
Error: Can't use fetch() in queries and mutations. Please consider using an action. See
Let me check the knowledge base for you again. One moment! :books:
You cannot use fetch() inside a Convex internalMutation (or any mutation/query), as Convex mutations and queries are strictly deterministic and do not allow side effects like network requests. This is enforced by the Convex runtime and is the reason for the error you are seeing:
Error: Can't use fetch() in queries and mutations. Please consider using an action.
How to solve this:
You need to move the code that calls sendDiscordNotification (which uses fetch) into a Convex action. The recommended pattern is:
- In your
internalMutation, schedule an action usingctx.scheduler.runAfterto handle the side effect (the Discord webhook call). - Move the
sendDiscordNotificationlogic into an action.
Example pattern:
// In your internalMutation
await ctx.scheduler.runAfter(0, internal.webhookEmail.notifyDiscord, {
id,
event,
});
Then, in your action file (can be "use node" if needed):
import { action } from './_generated/server';
import { sendDiscordNotification } from '../utils/discordwebhook';
import { v } from 'convex/values';
export const notifyDiscord = action({
args: {
id: v.string(),
event: v.any(), // Use appropriate validation
},
handler: async (ctx, args) => {
await sendDiscordNotification(process.env.DISCORD_WEBHOOK_URL, args.event, args.id, 'error');
},
});
This approach is the recommended and supported way to perform side effects (like HTTP requests) in response to database events in Convex (Best Practices, Tutorial: Actions, Stack: Pinecone and Embeddings).
Summary:
- You cannot use
fetch()in mutations or queries. - Use an action for side effects, and schedule it from your mutation using
ctx.scheduler.runAfter.