Skip to main content
AhaSend lets you send transactional email from Google Cloud Run functions in Node.js with the official SDK; this guide runs the same HTTP function locally with the Functions Framework. Cloud Run functions is the current name for the service previously called Cloud Functions.

Prerequisites

Use a verified sending domain, your account ID, and a domain-scoped send-only API v2 key. Use sandbox mode for every test. Management tasks need a separate full API key. Use Node.js 22 and the Node.js Functions Framework. A Google Cloud account is only needed when you deploy.

Install the Dependencies

Try a Sandbox Send

Run this short SDK check locally before adding the longer server integration below. Use a verified sender, a send-only API key, and your account ID. It sends to a reserved test address with sandbox: true, so no email is delivered. In the server project directory, add .env to .gitignore, then create .env with AHASEND_API_KEY, AHASEND_ACCOUNT_ID, and AHASEND_FROM (an address on your verified domain). Keep these values out of browser code and AI prompts. Use Node.js 22 or newer. Save this as quick-send.mjs:
quick-send.mjs
Run node --env-file=.env quick-send.mjs from that directory. The output lists each recipient status; queued or scheduled means accepted for sandbox processing. The process exits with a failure if the request or any recipient fails. Continue below for the full integration.

Add the Shared Sending Code

Save this as send-email.cjs beside the function file. Configure AHASEND_API_KEY, AHASEND_ACCOUNT_ID, AHASEND_FROM, AHASEND_TO and a long random SEND_TOKEN on the server. Set AHASEND_TO=recipient@example.com and AHASEND_DELIVERY_MODE=sandbox for local testing. Keep a sandbox credential until you are ready for real delivery; changing the mode to live alone cannot override a sandbox credential.
send-email.cjs
The caller supplies only the business event ID. For a real signup, read the recipient from your database after checking the caller’s access. Save the exact message with that event ID and reuse both when retrying. Read the idempotency limits before retrying an uncertain send. Add request limits at the hosting layer and log an internal event ID instead of credentials or message bodies.

Create the HTTP Function

Save this as index.cjs:
index.cjs

Run with the Functions Framework

If port 8080 is busy, set PORT to an unused local port in both shells. The commands below default to 8080. Export the shared code’s environment variables before starting the local server:
In another shell with SEND_TOKEN set, run:
Expect HTTP 202 with acceptance statuses. The handler refuses non-POST requests, missing tokens and invalid event IDs. A fresh test needs a new event ID; an exact retry keeps the old one.

Prepare the Hosted Function

Choose the Node.js 22 runtime and entry point sendEmail. Follow Google’s function deployment steps. Put secrets in Secret Manager, allow only trusted invokers, and cap requests before they create mail jobs. When Cloud Run IAM and the app token are both in use, put the Google identity token in X-Serverless-Authorization and keep the app token in Authorization, as described in Google’s service authentication guide. Use webhooks to track final delivery. Also see Google functions in Python, Go and Node.js SMTP.