Skip to content
decodecodeveloper docs
Storefront → Templates → Commerce

Resend

Configure transactional email for a Blocks 7.x site.

@decocms/apps-resend sends transactional email from the server. The website owns the form and its validation; the app supplies the provider integration. Use the 7.x runtime reference for the full contract.

Configuration

Block

Configure sender, recipients, and default subject:

.deco/blocks/deco-resend.json
{
  "__resolveType": "deco-resend",
  "emailFrom": { "name": "My Store", "domain": "hello@store.example.com" },
  "emailTo": ["team@store.example.com"],
  "subject": "Contact form submission"
}

emailFrom.domain is the full sender address, despite its name. Verify that sender's domain with Resend. Set RESEND_API_KEY in the server environment; autoconfiguration resolves it when the block has no saved key. Encrypted keys use the integration's secret mechanism.

Wiring

Run this after framework setup, on the server:

src/setup/apps.ts
import { autoconfigApps, type AppRegistry } from "@decocms/blocks-admin/apps";
import { loadBlocks } from "@decocms/blocks/cms";
import { RESEND_REGISTRY_ENTRY } from "@decocms/apps-resend/registry";
import * as resendMod from "@decocms/apps-resend/mod";
 
const APP_REGISTRY: AppRegistry = [
  { ...RESEND_REGISTRY_ENTRY, module: async () => resendMod },
];
 
await autoconfigApps(loadBlocks(), APP_REGISTRY);

There is no implicit Resend registry entry. Alternatively, configure the client with configureResend from @decocms/apps-resend/client and a key resolved by your server code.

Sending email

Create an action with fixed server-side recipient defaults, rather than exposing arbitrary recipient inputs to the browser:

src/actions/contact.ts
import { sendEmail } from "@decocms/apps-resend";
 
export interface Props {
  email: string;
  message: string;
}
 
export default async function contact(props: Props) {
  const { data, error } = await sendEmail({
    reply_to: props.email,
    text: props.message,
  });
  if (error) return { ok: false, reason: error.name };
  return { ok: true, id: data?.id };
}

The normal provider result is { data, error }: success contains data.id; validation or provider errors populate error. Network/timeouts and missing runtime configuration can still throw. Handle both according to your application's delivery policy.

Inputs

Payload fields include from, to, subject, html, text, and reply_to. Passed values override configured defaults. See the supported fields.

Outputs

An accepted provider response identifies a message; it does not establish final delivery. Observe delivery status through your provider integration.

Use cases

Contact forms and transactional notifications are typical uses. Decide whether the commerce platform already sends the notification before adding a second sender.

Templates

Render email templates on the server and pass the HTML to sendEmail.

Custom invoke handlers

Put a validated site action such as contact in src/actions/ and run the framework generator to register it. The app integration does not supply a universal browser email endpoint. See Loaders and actions.

Rate limits

Use the provider's current quota and delivery requirements when deciding whether to queue sends. An asynchronous send still needs its provider result handled; do not discard error.

Stability

These instructions target the released 7.x integration. App configuration is edited in the Site Editor and deployed through your repository workflow.

See also