# Send emails with Make

> Send from a Make scenario with the HTTP module.

## What you'll build

A Make scenario that sends email through PostShiba with the HTTP app's **Make a request** module. You can also start scenarios from PostShiba delivery events with the Webhooks app.

## Before you start

- An API key with **Full access**. See [Create an API key](/docs/create-an-api-key). Support keys cannot send.
- A verified sending domain. See [Add and verify a domain](/docs/add-a-domain). `from` must be an address on it.
- A **Transactional** cluster that is ready to send. One-off notifications from a scenario belong on a transactional cluster, and the type is locked after create. See [Clusters](/docs/dashboard/clusters/introduction).

## Install

Nothing to install. The HTTP and Webhooks apps are built into Make.

## Send your first email

1. Add the **HTTP** app's **Make a request** module to your scenario.
2. Set **Authentication type** to **API key**. Under **Credentials**, create a keychain with **Key** `Bearer YOUR_API_KEY`, **API key placement** **In the header**, and **API key parameter name** `Authorization`.
3. Fill in the request with these values.

```text make-http.txt
Authentication type:     API key
Key:                     Bearer YOUR_API_KEY
API key placement:       In the header
API key parameter name:  Authorization
URL:                     https://app.postshiba.com/api/v1/emails
Method:                  POST
Body content type:       application/json
Body input method:       JSON string
Body content:            {"from": "hello@mail.example.com", "to": "you@example.com", "subject": "Your receipt", "text": "Thanks for your order."}
Parse response:          Yes
```

4. Run the module once. A queued send returns `201` with `"queued": true`. The message then shows under Events in the dashboard.

To map values from earlier modules, set **Body input method** to **Data structure** and add `from`, `to`, `subject`, `text`, and `html` as text fields. Make escapes quotes and other JSON characters in mapped values for you. A **JSON string** body is sent as typed, so a mapped subject with a quote in it breaks the JSON.

`to` takes one address or a comma-separated string. Every field is on [Send emails with HTTP](/docs/send-with-http). To send on a specific cluster, add an `X-Capsule-Cluster-Id` header under **Headers**.

Under advanced settings, set **Return error if HTTP request fails** to **Yes** so a refused send stops the scenario instead of passing on as a success.

## React to delivery events

PostShiba POSTs each delivery event to a URL as a JSON array in the SendGrid Event Webhook format. The **Webhooks** app's **Custom webhook** module can receive it and start a scenario.

1. Add **Webhooks** > **Custom webhook** as the first module. Next to **Webhook**, click **Add**, enter a **Webhook name**, and click **Save**. Copy the URL Make generates.
2. In PostShiba, open **Webhooks**, click **Add endpoint**, paste the URL, and save. See [Managing webhooks](/docs/webhooks/introduction).
3. Run the scenario once so the module listens, then click **Send test event** on the endpoint in PostShiba. Make learns the event fields from the request. The test event has `"test": true`.
4. Map fields such as `event`, `email`, and `sg_event_id` in later modules. Fields on each event are on [Event types](/docs/webhooks/event-types).

To read the `X-Capsule-Signature` and `X-Capsule-Timestamp` headers, turn on **Get request headers** in the webhook's advanced settings. Checking the signature needs the exact raw request body. To check every request, point the endpoint at a server you control and follow [Verify webhook requests](/docs/webhooks/verify-webhooks-requests). Anyone who has the Make webhook URL can start the scenario, so keep it private.

## Troubleshooting

| What you see | What to do |
| --- | --- |
| `401` `Invalid token or no user signed in` | Check the keychain. **Key** must be `Bearer ` followed by your API key, and **API key parameter name** must be `Authorization`. |
| `403` `forbidden` | Support keys cannot send. Use a Full access key. |
| `403` `domain_unverified` or `domain_suspended` | Use a `from` address on a verified domain. Resume a paused domain from [Managing domains](/docs/dashboard/domains/manage-domains). |
| `403` `kyc_required` | Your team is pending production approval. Until then, send only to team members, live inbox addresses, and inbox forward-to addresses. See [Does PostShiba require production approval?](/docs/knowledge-base/does-capsule-require-production-approval) |
| `422` `invalid` | `field` names the problem, such as a missing `to`. With **JSON string**, check that the body is valid JSON, or switch to **Data structure**. |
| `429` `throttled` | The cluster hit its hourly throttle or 24-hour cap. Retrying right away hits the same cap. See [What happens at your cap](/docs/dashboard/clusters/what-happens-at-your-cap). |
| `429` `rate_limited` | More than 300 send requests in one minute on one API key. Slow the scenario down. |
| `403` `suppressed` or `403` `firewall` | Every recipient is on the [suppression list](/docs/dashboard/emails/email-suppressions), or the send failed an [email firewall](/docs/dashboard/emails/email-firewall) rule. When only some recipients are suppressed, the rest are sent and the response lists the skipped ones in `suppressed`. |

## Next steps

- [Send emails with HTTP](/docs/send-with-http) for every field on the send request.
- [Unique args](/docs/dashboard/emails/unique-args) to get your own ids back on delivery webhooks.
- [Event types](/docs/webhooks/event-types)
- [Verify webhook requests](/docs/webhooks/verify-webhooks-requests)
