# Forward received emails

> Forward an inbound email to another address — either with the built-in forward endpoint, or by downloading the raw message, parsing it, and re-sending via POST /emails.

Received emails can be **forwarded** on to another address. There are two approaches: the built-in **forward endpoint**, which re-sends the stored parsed message body **with the original attachments** (inline images preserved) in one call, or a **manual re-send**, where you download and parse the raw message yourself for full RFC 5322 fidelity.

> **Warning:** Webhooks include metadata only — not the body, headers, or attachment content. Retrieve the message with the [Receiving API](https://www.mailblastr.com/docs/receiving/get-email-content) (and the [Attachments API](https://www.mailblastr.com/docs/receiving/attachments) for files) before forwarding.

## Forward endpoint

The quickest way to forward is [`POST /emails/receiving/:id/forward`](https://www.mailblastr.com/docs/api/emails-send). It re-sends the received email's stored parsed `subject`, `html`, and `text` — along with the original attachments — as a new outbound email. Pass `from` (required) and the recipient(s); the original subject, body, and files are reused.

**Body**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `from` | string | No | Required. The sender address for the forwarded message. Must be an address on a [verified sending domain](https://www.mailblastr.com/docs/domains/managing). |
| `to` | string | string[] | No | The recipient address(es) to forward to. |

**Node.js**

```js
import { MailBlastr } from 'mailblastr';

const mb = new MailBlastr('mb_xxxxxxxxx');

const { data, error } = await mb.emails.receiving.forward('56761188-7520-42d8-8898-ff6fc54ce618', {
  "from": "Acme <hello@yourdomain.com>",
  "to": ["delivered@example.com"]
});
console.log({ data, error });
```

**Ruby**

```ruby
require "mailblastr"

Mailblastr.api_key = "mb_xxxxxxxxx"

Mailblastr::Emails::Receiving.forward("56761188-7520-42d8-8898-ff6fc54ce618", {
  "from": "Acme <hello@yourdomain.com>",
  "to": [
    "delivered@example.com"
  ]
})
```

**PHP**

```php
$mailblastr = Mailblastr::client('mb_xxxxxxxxx');

$mailblastr->emails->receiving->forward('56761188-7520-42d8-8898-ff6fc54ce618', [
  'from' => "Acme <hello@yourdomain.com>",
  'to' => [
    "delivered@example.com"
  ]
]);
```

**Python**

```python
import mailblastr

mailblastr.api_key = "mb_xxxxxxxxx"

mailblastr.Emails.Receiving.forward("56761188-7520-42d8-8898-ff6fc54ce618", {
  "from": "Acme <hello@yourdomain.com>",
  "to": [
    "delivered@example.com"
  ]
})
```

**Go**

```go
package main

import (
    "fmt"
    "io"
    "net/http"
    "strings"
)

func main() {
    req, _ := http.NewRequest("POST", "https://api.mailblastr.com/emails/receiving/56761188-7520-42d8-8898-ff6fc54ce618/forward", strings.NewReader(`{
  "from": "Acme <hello@yourdomain.com>",
  "to": ["delivered@example.com"]
}`))
    req.Header.Set("Authorization", "Bearer mb_xxxxxxxxx")
    req.Header.Set("Content-Type", "application/json")
    res, _ := http.DefaultClient.Do(req)
    defer res.Body.Close()
    out, _ := io.ReadAll(res.Body)
    fmt.Println(string(out))
}
```

**Rust**

```rust
use reqwest::Client;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let res = Client::new()
        .post("https://api.mailblastr.com/emails/receiving/56761188-7520-42d8-8898-ff6fc54ce618/forward")
        .header("Authorization", "Bearer mb_xxxxxxxxx")
        .header("Content-Type", "application/json")
        .body(r#"{
  "from": "Acme <hello@yourdomain.com>",
  "to": ["delivered@example.com"]
}"#)
        .send()
        .await?;
    println!("{}", res.text().await?);
    Ok(())
}
```

**Java**

```java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.mailblastr.com/emails/receiving/56761188-7520-42d8-8898-ff6fc54ce618/forward"))
    .header("Authorization", "Bearer mb_xxxxxxxxx")
    .header("Content-Type", "application/json")
    .method("POST", HttpRequest.BodyPublishers.ofString("""
{
  "from": "Acme <hello@yourdomain.com>",
  "to": ["delivered@example.com"]
}
"""))
    .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
```

**.NET**

```csharp
using System.Net.Http;
using System.Text;

var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://api.mailblastr.com/emails/receiving/56761188-7520-42d8-8898-ff6fc54ce618/forward");
request.Headers.Add("Authorization", "Bearer mb_xxxxxxxxx");
request.Content = new StringContent(@"{
  ""from"": ""Acme <hello@yourdomain.com>"",
  ""to"": [""delivered@example.com""]
}", Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);
Console.WriteLine(await response.Content.ReadAsStringAsync());
```

**cURL**

```bash
curl -X POST 'https://api.mailblastr.com/emails/receiving/56761188-7520-42d8-8898-ff6fc54ce618/forward' \
  -H 'Authorization: Bearer mb_xxxxxxxxx' \
  -H 'Content-Type: application/json' \
  -d '{
  "from": "Acme <hello@yourdomain.com>",
  "to": ["delivered@example.com"]
}'
```

**CLI**

```bash
mailblastr emails receiving forward 56761188-7520-42d8-8898-ff6fc54ce618 \
  --from 'Acme <hello@yourdomain.com>' \
  --to 'delivered@example.com'
```

> **Note:** The forward endpoint re-sends the parsed subject and body **and** re-attaches the original attachments — inline images are preserved via their `content_id`, so embedded images still render. Attachments are best-effort: any whose stored bytes can't be loaded are skipped, and the same per-attachment / total size caps as a normal send apply. For full RFC 5322 fidelity (exact original MIME, custom headers), use the manual re-send below instead.

## Forward by re-sending

The most faithful way to forward is to download the **raw** RFC 5322 message and parse it, so you correctly extract the HTML/text bodies and every attachment — especially inline images referenced by `Content-ID`. Then re-send the extracted content with [POST /emails](https://www.mailblastr.com/docs/api/emails-send).

The retrieved received email exposes a `raw.download_url` you can fetch to get the original bytes. Strip the angle brackets from each inline part's `content_id` so the forwarded HTML still resolves its embedded images.

**Node.js**

```js
// app/api/events/route.ts
import type { NextRequest } from 'next/server';
import { NextResponse } from 'next/server';
import { simpleParser } from 'mailparser';

const API_KEY = 'mb_xxxxxxxxx';

export const POST = async (request: NextRequest) => {
  const event = await request.json();

  if (event.type === 'email.received') {
    // 1. Get the received email (includes raw.download_url)
    const metaRes = await fetch(
      `https://api.mailblastr.com/emails/receiving/${event.data.email_id}`,
      { headers: { Authorization: `Bearer ${API_KEY}` } },
    );
    const email = await metaRes.json();

    if (!email?.raw?.download_url) {
      return new NextResponse('Raw email not available', { status: 500 });
    }

    // 2. Download and parse the raw RFC 5322 message
    const rawResponse = await fetch(email.raw.download_url);
    const rawEmailContent = await rawResponse.text();
    const parsed = await simpleParser(rawEmailContent, { skipImageLinks: true });

    // 3. Re-build attachments, keeping inline content_ids
    const attachments = parsed.attachments.map((attachment) => {
      const contentId = attachment.contentId
        ? attachment.contentId.replace(/^<|>$/g, '')
        : undefined;
      return {
        filename: attachment.filename,
        content: attachment.content.toString('base64'),
        content_type: attachment.contentType,
        content_id: contentId || undefined,
      };
    });

    // 4. Forward by sending a new email
    const sendRes = await fetch('https://api.mailblastr.com/emails', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        from: 'Acme <hello@yourdomain.com>',
        to: ['delivered@example.com'],
        subject: email.subject || '(no subject)',
        html: parsed.html || undefined,
        text: parsed.text || undefined,
        attachments: attachments.length > 0 ? attachments : undefined,
      }),
    });

    return NextResponse.json(await sendRes.json());
  }

  return NextResponse.json({});
};
```

**Python**

```python
import base64, email as email_lib, requests
from email import policy
from flask import Flask, request, jsonify

app = Flask(__name__)
API_KEY = "mb_xxxxxxxxx"

@app.post("/api/events")
def events():
    event = request.get_json()
    if event.get("type") != "email.received":
        return jsonify({})

    # 1. Get the received email (includes raw.download_url)
    meta = requests.get(
        f"https://api.mailblastr.com/emails/receiving/{event['data']['email_id']}",
        headers={"Authorization": f"Bearer {API_KEY}"},
    ).json()

    raw = (meta.get("raw") or {}).get("download_url")
    if not raw:
        return "Raw email not available", 500

    # 2. Download and parse the raw RFC 5322 message
    raw_bytes = requests.get(raw).content
    parsed = email_lib.message_from_bytes(raw_bytes, policy=policy.default)

    html = parsed.get_body(("html",))
    text = parsed.get_body(("plain",))

    attachments = []
    for part in parsed.iter_attachments():
        cid = part.get("Content-ID")
        attachments.append({
            "filename": part.get_filename(),
            "content": base64.b64encode(part.get_content()).decode(),
            "content_type": part.get_content_type(),
            "content_id": cid.strip("<>") if cid else None,
        })

    # 3. Forward by sending a new email
    sent = requests.post(
        "https://api.mailblastr.com/emails",
        headers={"Authorization": f"Bearer {API_KEY}"},
        json={
            "from": "Acme <hello@yourdomain.com>",
            "to": ["delivered@example.com"],
            "subject": meta.get("subject") or "(no subject)",
            "html": html.get_content() if html else None,
            "text": text.get_content() if text else None,
            "attachments": attachments or None,
        },
    )
    return jsonify(sent.json())
```

> **Note:** The Node.js example uses [`mailparser`](https://www.npmjs.com/package/mailparser) (`npm install mailparser`). In any language, use an [RFC 5322](https://datatracker.ietf.org/doc/html/rfc5322)-capable parser — the example above uses Python's built-in `email` package.

## Forward style: passthrough vs. wrapped

Re-sending the parsed `html`/`text` and attachments reproduces the original message as it arrived — a clean **passthrough** forward. If you instead want a "forwarded message" footer like an email client, send your own intro `html`/`text` and append the original content (and a quoted header block) beneath it:

```js
const footer = `
  <p>See attached forwarded message.</p>
  <hr>
  <p>---------- Forwarded message ----------<br>
     From: ${email.from}<br>
     Subject: ${email.subject}</p>
`;

await fetch('https://api.mailblastr.com/emails', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    from: 'Acme <hello@yourdomain.com>',
    to: ['delivered@example.com'],
    subject: `Fwd: ${email.subject || '(no subject)'}`,
    html: footer + (parsed.html || ''),
    attachments: attachments.length > 0 ? attachments : undefined,
  }),
});
```

> **Warning:** The forwarding `from` must be an address on a [verified sending domain](https://www.mailblastr.com/docs/domains/managing) — it is a brand-new outbound send via `POST /emails`, not a relay of the original envelope.
