Send from any automation tool's HTTP step
Automation tools can send email through Groundmail with their generic HTTP request step. No Groundmail app is needed: the step calls the Groundmail API directly.
This page covers the request every tool makes, then the details for Make, Pabbly Connect, Pipedream and Integrately. Zapier has its own guide: Zapier. For n8n, see the n8n community node.
Before you start
- A verified sending domain.
- A Groundmail API key. Create one under API Keys in the dashboard. Choose Send only, and limit it to your sending domain with the allowed domains option. Anyone who can edit the workflow can read the key, so keep its access narrow. See API keys.
The request
| Setting | Value |
|---|---|
| Method | POST |
| URL | https://api.groundmail.dev/emails |
| Header | Authorization: Bearer gm_… (the word Bearer, a space, then your key) |
| Header | Content-Type: application/json |
| Body | JSON, below |
{
"from": "notifications@yourdomain.com",
"to": "user@example.com",
"subject": "Your order has shipped",
"html": "<p>Your order is on its way.</p>",
"text": "Your order is on its way."
}Replace to, subject and the body with values from your trigger. from must be on a verified domain, and at least one of html or text is required. See Emails for every field, including reply_to, cc, bcc and tags.
When you map a value into a JSON string, an unescaped quote in that value breaks the JSON and the request fails with a 400.
Make retries harmless
Add an Idempotency-Key header with a value that is unique per event (an order id, for example). For 24 hours Groundmail returns the original response instead of sending twice, so a re-run or retried step doesn't send a duplicate. See Idempotency.
Test it
Build with a test key (gm_test_…, created by ticking Test key on the API Keys page). Groundmail runs the whole pipeline but delivers nothing, so any recipient works. A successful response looks like this:
{ "id": "msg_…", "status": "sent", "test": true }You can also use a live key and send to delivered@simulator.groundmail.dev, which never reaches a real inbox. Use bounce@simulator.groundmail.dev to see a hard bounce. The full list is in Testing. The email shows up under Emails in the Groundmail dashboard. When you are done, replace the test key with a live key.
To react to delivery, bounces or complaints after Groundmail accepted the message, create a webhook that points to your tool's webhook trigger URL.
Errors
Groundmail errors are JSON with a stable code, a message and a hint. See Errors.
| Status | Meaning | What to do |
|---|---|---|
401 unauthorized |
The key is missing or wrong. | The header value must be Bearer gm_…, with the word Bearer and a space. Check the key is active on the API Keys page. |
403 forbidden |
The domain in from is not verified, or the account is still on the sandbox sender, which only sends to your own account email. |
Verify the domain under Domains. |
403 domain_not_allowed |
The key is limited to other domains. | Use a key allowed for this from domain. |
403 insufficient_scope |
The key cannot send. | Use a Send only or full-access key. |
400 validation_error |
A required field is missing or empty, to is not a valid address, or the body is not valid JSON. |
The message and details say which field. |
422 validation_error with suppressed |
Every recipient is on your suppression list or was held back as unable to receive mail. | Don't retry the same address. See Suppressions. |
| 429 | You hit a sending limit. | See Sending limits. |
Make
Use the HTTP app's Make a request module.
| Make field | Value |
|---|---|
| URL | https://api.groundmail.dev/emails |
| Method | POST |
| Authentication type | API key |
| Body content type | application/JSON |
| Body input method | JSON string |
| Parse response | Yes |
| Return error if HTTP request fails | Yes |
For Credentials, create a new API key credential. Put the key in the header, name the parameter Authorization, and enter Bearer gm_… as the key. Make's documentation recommends the credentials field over defining authentication in the request headers. If you'd rather set it by hand, leave Authentication type as No authentication and add an Authorization: Bearer gm_… entry in Headers.
Map values from earlier modules into the JSON body, for example "to": "{{1.email}}", where {{1.email}} is a field from module 1 picked in Make's mapping panel.
With Return error if HTTP request fails set to Yes, the scenario stops on a 4xx or 5xx response, and the response body explains why.
Pabbly Connect
Add an action step, search for API by Pabbly, and choose the POST action event. Field names differ slightly between Pabbly's interface versions, so match them by meaning:
| Pabbly setting | Value |
|---|---|
| Endpoint URL | https://api.groundmail.dev/emails |
| Payload type | JSON |
| Headers | Authorization = Bearer gm_… |
Then add from, to, subject, html and text as body fields. To paste the whole body instead, choose the Custom Request action event and enter the JSON in the data section, or use Pabbly's cURL import with this request:
curl -X POST https://api.groundmail.dev/emails \
-H "Authorization: Bearer gm_…" \
-H "Content-Type: application/json" \
-d '{"from":"notifications@yourdomain.com","to":"user@example.com","subject":"Hello","html":"<p>Hi</p>"}'Test with Send Test Request (or Save and Send Test Request) on the step.
Pipedream
Use a Node.js code step. It can retry and handle errors; the Send any HTTP Request action cannot.
First store the key: go to Settings, then Environment Variables, click New Variable, and save your key as GROUNDMAIL_API_KEY. New variables are secret by default. For a variable that belongs to one project, open the project and use Variables instead. Don't log the key in a step: logged values appear in the step's logs.
Then add a Node.js code step after your trigger. It uses the axios wrapper from @pipedream/platform, which Pipedream provides in code steps:
import { axios } from "@pipedream/platform"
export default defineComponent({
async run({ steps, $ }) {
return await axios($, {
url: "https://api.groundmail.dev/emails",
method: "post",
headers: {
Authorization: `Bearer ${process.env.GROUNDMAIL_API_KEY}`,
"Idempotency-Key": `welcome-${steps.trigger.event.user_id}`,
},
data: {
from: "notifications@yourdomain.com",
to: steps.trigger.event.email,
subject: "Welcome",
html: "<p>Thanks for signing up.</p>",
text: "Thanks for signing up.",
},
})
},
})Change steps.trigger.event.email and steps.trigger.event.user_id to the fields your trigger provides. If the request fails, the axios wrapper surfaces the Groundmail error body; wrap the call in try...catch to retry or branch on code. If process.env.GROUNDMAIL_API_KEY is undefined, the variable name doesn't match (names are case-sensitive).
Without code, the Send any HTTP Request action takes the same method, URL, header and body. Pipedream notes this action halts the workflow when the request fails and cannot retry on its own.
To receive Groundmail webhooks, add an HTTP / Webhook trigger to a second workflow and register its URL (https://YOUR-ENDPOINT.m.pipedream.net) as a webhook.
Integrately
Set Webhook/API as the action app, choose the POST method, and enter the URL, the two headers and the JSON body from the request. Integrately's documentation doesn't name every field on the action screen, so match the settings by what they do.
If the action screen has no field for headers or a JSON body, Integrately can't make this request in that automation. Use Zapier, Make or Pabbly Connect instead.