# Send a reply from a connected mailbox

Source: https://docs.emelia.io/docs/replies/send-reply

Guide: [Replies](https://docs.emelia.io/docs/replies.md)

`POST https://api.emelia.io/emails/reply`

Sends an e-mail from one of your connected providers. At least one of providerId or senderEmail is required to pick the mailbox. With messageId (from the merged inbox) the message is threaded (In-Reply-To, References, quoted history appended); without it you must supply to and subject yourself. content is HTML (use <br> for line breaks). scheduledAt (ISO) schedules the send instead of sending now. New integrations should use the multichannel /advanced campaign endpoints instead.

> **Deprecated.**

## Authentication

Send your API key in the `Authorization` header: `Authorization: <your API key>`.

## Request body

Content type: `application/json`, required.

| Field | Type | Required | Description |
|---|---|---|---|
| `senderEmail` | string (email) | no | Sender mailbox address (alternative to providerId). |
| `providerId` | string | no | Provider ObjectId (alternative to senderEmail). |
| `messageId` | string | no | Message-ID of the email to reply to. Threads the reply. If Emelia cannot find it, the call fails with 'Original message not found'. |
| `subject` | string or null | no |  |
| `content` | string | yes | HTML body. Use <br> for line breaks. |
| `scheduledAt` | string (date-time) | no | ISO date to schedule the send. |
| `attachments` | array of object | no |  |
| `attachments[].name` | string | no |  |
| `attachments[].url` | string (uri) | no |  |
| `to` | array of string | no |  |
| `cc` | array of string | no |  |
| `bcc` | array of string | no |  |

```json
{
  "providerId": "5f3a1b2c4d5e6f0011223344",
  "to": [
    "jane.roe@acme.com"
  ],
  "subject": "Re: your question",
  "content": "Hello Jane,<br><br>Thanks for your reply."
}
```

## Example request

**cURL**

```bash
curl -X POST "https://api.emelia.io/emails/reply" \
  -H "Authorization: $EMELIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "providerId": "5f3a1b2c4d5e6f0011223344",
  "to": [
    "jane.roe@acme.com"
  ],
  "subject": "Re: your question",
  "content": "Hello Jane,<br><br>Thanks for your reply."
}'
```

**JavaScript**

```js
const response = await fetch('https://api.emelia.io/emails/reply', {
  method: 'POST',
  headers: { Authorization: process.env.EMELIA_API_KEY, 'Content-Type': 'application/json' },
  body: JSON.stringify({
    "providerId": "5f3a1b2c4d5e6f0011223344",
    "to": [
      "jane.roe@acme.com"
    ],
    "subject": "Re: your question",
    "content": "Hello Jane,<br><br>Thanks for your reply."
  }),
});
console.log(await response.json());
```

**Python**

```python
import os
import requests

response = requests.post(
    "https://api.emelia.io/emails/reply",
    headers={"Authorization": os.environ["EMELIA_API_KEY"]},
    json={
        "providerId": "5f3a1b2c4d5e6f0011223344",
        "to": [
            "jane.roe@acme.com"
        ],
        "subject": "Re: your question",
        "content": "Hello Jane,<br><br>Thanks for your reply."
    },
)
print(response.json())
```

## Responses

### 200: Reply sent (or scheduled).

| Field | Type | Required | Description |
|---|---|---|---|
| `success` | enum: `true` | yes |  |

```json
{
  "success": true
}
```

### 400: Business or validation error. 400 by default; Joi validation errors carry code INVALID_REQUEST.

| Field | Type | Required | Description |
|---|---|---|---|
| `error` | string or object | yes | Human readable message. A few legacy routes return an empty object `{}` here instead of a string. |
| `code` | enum: `INVALID_REQUEST`, `INVALID_PARAMETERS`, `SUBSCRIPTION_REQUIRED`, `CAMPAIGN_NOT_FOUND`, `CAMPAIGN_ALREADY_RUNNING`, `SCHEDULE_MISSING`, `STEPS_MISSING`, `NO_RECIPIENTS`, `TOO_MANY_RECIPIENTS`, `PLANNED_START_INVALID`, `PLANNED_START_IN_PAST`, `EMAIL_PROVIDER_MISSING`, `EMAIL_PROVIDER_DISCONNECTED`, `EMAIL_PROVIDER_EXPIRED`, `ONE_EMAIL_PROVIDER_EXPIRED`, `EMAIL_ADDRESS_DISCONNECTED`, `TRACKING_DOMAINS_REQUIRED`, `LINKEDIN_ACCOUNT_MISSING`, `LINKEDIN_COOKIE_EXPIRED`, `LINKEDIN_SLOT_EXPIRED`, `WHATSAPP_ACCOUNT_EXPIRED`, `WHATSAPP_SLOT_EXPIRED`, `NO_IDENTITY_SET`, `IDENTITY_FOREIGN_ACCOUNT`, `IDENTITY_EMAIL_PROVIDER_MISSING`, `LINKEDIN_ACCOUNT_AMBIGUOUS`, `WHATSAPP_ACCOUNT_AMBIGUOUS`, `LINKEDIN_AUDIO_MISSING`, `EMAIL_STEP_NO_ACTIVE_VERSION`, `EMAIL_VERSION_NO_CONTENT`, `EMAIL_VERSION_NO_SUBJECT`, `RECIPIENTS_NO_EMAIL`, `RECIPIENTS_NO_LINKEDIN`, `MC_LINKEDIN_DAILY_LIMIT_CONNECTION`, `MC_LINKEDIN_DAILY_LIMIT`, `DAILY_CONTACT_TOO_LOW`, `LINKEDIN_DAILY_CONTACT_LIMIT`, `VERIFY_EMAIL_TOKEN_INVALID`, `VERIFY_EMAIL_TOKEN_EXPIRED`, `FREE_CREDITS_DOMAIN_ALREADY_CLAIMED`, `FREE_CREDITS_ALREADY_GRANTED`, `FREE_CREDITS_NOT_ELIGIBLE`, `RATE_LIMITED`, `STATS_COMPUTING`, `WARMUP_PROVIDER_UNSUPPORTED`, `ACCOUNT_DISCONNECTED` | no | Stable machine readable error code. Present only on catalogued errors (mainly the campaign start checks), on validation errors (`INVALID_REQUEST`) and on some LinkedIn provider errors (`ACCOUNT_DISCONNECTED`, `RATE_LIMITED`). Most other errors have no code: rely on the HTTP status and on `error`. Codes are never renamed once deployed. |
| `params` | object | no | Values interpolated in the message, for example `{"max": 30000}`. |

```json
{
  "error": "string",
  "code": "INVALID_REQUEST",
  "params": {}
}
```
