# Examples

> Copy-paste recipes for the most common MailBlastr tasks — sending, batching, scheduling, attachments, contacts, and webhooks — using nothing but an HTTP client.

MailBlastr is a plain JSON REST API with official SDKs for Node.js, Ruby, PHP, Python, Go, Rust, Java, and .NET (plus a CLI) — see the [install table](https://www.mailblastr.com/docs/api/introduction). Every endpoint page in these docs carries a copyable tab for each of them alongside raw **cURL**.

The snippets below string those endpoints together into the recipes people ask for most. Swap `mb_xxxxxxxxx` for your API key and `yourdomain.com` for a [verified domain](https://www.mailblastr.com/docs/domains/managing).

## Send your first email

The smallest useful request — a single transactional email from a verified domain. See [Send an email](https://www.mailblastr.com/docs/api/emails-send).

**Node.js**

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

const mb = new MailBlastr('mb_xxxxxxxxx');

const { data, error } = await mb.emails.send({
  "from": "Acme <hello@yourdomain.com>",
  "to": ["user@example.com"],
  "subject": "Hello from MailBlastr",
  "html": "<p>Your first email 🎉</p>"
});
console.log({ data, error });
```

**Ruby**

```ruby
require "mailblastr"

Mailblastr.api_key = "mb_xxxxxxxxx"

Mailblastr::Emails.send({
  "from": "Acme <hello@yourdomain.com>",
  "to": [
    "user@example.com"
  ],
  "subject": "Hello from MailBlastr",
  "html": "<p>Your first email 🎉</p>"
})
```

**PHP**

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

$mailblastr->emails->send([
  'from' => "Acme <hello@yourdomain.com>",
  'to' => [
    "user@example.com"
  ],
  'subject' => "Hello from MailBlastr",
  'html' => "<p>Your first email 🎉</p>"
]);
```

**Python**

```python
import mailblastr

mailblastr.api_key = "mb_xxxxxxxxx"

mailblastr.Emails.send({
  "from": "Acme <hello@yourdomain.com>",
  "to": [
    "user@example.com"
  ],
  "subject": "Hello from MailBlastr",
  "html": "<p>Your first email 🎉</p>"
})
```

**Go**

```go
import "github.com/shekhu10/mailblastr-sdks/mailblastr-go"

client := mailblastr.NewClient("mb_xxxxxxxxx")

params := &mailblastr.SendEmailRequest{
    From:    "Acme <hello@yourdomain.com>",
    To:      []string{"delivered@example.com"},
    Subject: "hello world",
    Html:    "<p>it works!</p>",
}
sent, err := client.Emails.Send(params)
```

**Rust**

```rust
use mailblastr::{Mailblastr, CreateEmailBaseOptions};

let mb = Mailblastr::new("mb_xxxxxxxxx");

let email = CreateEmailBaseOptions::new(
    "Acme <hello@yourdomain.com>",
    ["delivered@example.com"],
    "hello world",
).with_html("<p>it works!</p>");
let _sent = mb.emails.send(email).await?;
```

**Java**

```java
import com.mailblastr.*;

Mailblastr mailblastr = new Mailblastr("mb_xxxxxxxxx");

SendEmailRequest request = SendEmailRequest.builder()
    .from("Acme <hello@yourdomain.com>")
    .to("delivered@example.com")
    .subject("hello world")
    .html("<p>it works!</p>")
    .build();
mailblastr.emails().send(request);
```

**.NET**

```csharp
using Mailblastr;

IMailblastr mailblastr = MailblastrClient.Create("mb_xxxxxxxxx");

var resp = await mailblastr.EmailSendAsync(new EmailMessage
{
    From = "Acme <hello@yourdomain.com>",
    To = "delivered@example.com",
    Subject = "hello world",
    HtmlBody = "<p>it works!</p>",
});
```

**cURL**

```bash
curl -X POST 'https://api.mailblastr.com/emails' \
  -H 'Authorization: Bearer mb_xxxxxxxxx' \
  -H 'Content-Type: application/json' \
  -d '{
  "from": "Acme <hello@yourdomain.com>",
  "to": ["user@example.com"],
  "subject": "Hello from MailBlastr",
  "html": "<p>Your first email 🎉</p>"
}'
```

**CLI**

```bash
mailblastr emails send \
  --from 'Acme <hello@yourdomain.com>' \
  --to 'user@example.com' \
  --subject 'Hello from MailBlastr' \
  --html '<p>Your first email 🎉</p>'
```

## Send with an attachment

Inline a file as base64 `content`, or hand MailBlastr a hosted `path` URL to fetch at send time. See [Attachments](https://www.mailblastr.com/docs/emails/attachments).

**Node.js**

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

const mb = new MailBlastr('mb_xxxxxxxxx');

const { data, error } = await mb.emails.send({
  "from": "Acme <hello@yourdomain.com>",
  "to": ["user@example.com"],
  "subject": "Your invoice",
  "html": "<p>Invoice attached.</p>",
  "attachments": [
    { "filename": "invoice.pdf", "path": "https://files.example.com/invoice.pdf" }
  ]
});
console.log({ data, error });
```

**Ruby**

```ruby
require "mailblastr"

Mailblastr.api_key = "mb_xxxxxxxxx"

Mailblastr::Emails.send({
  "from": "Acme <hello@yourdomain.com>",
  "to": [
    "user@example.com"
  ],
  "subject": "Your invoice",
  "html": "<p>Invoice attached.</p>",
  "attachments": [
    {
      "filename": "invoice.pdf",
      "path": "https://files.example.com/invoice.pdf"
    }
  ]
})
```

**PHP**

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

$mailblastr->emails->send([
  'from' => "Acme <hello@yourdomain.com>",
  'to' => [
    "user@example.com"
  ],
  'subject' => "Your invoice",
  'html' => "<p>Invoice attached.</p>",
  'attachments' => [
    [
      'filename' => "invoice.pdf",
      'path' => "https://files.example.com/invoice.pdf"
    ]
  ]
]);
```

**Python**

```python
import mailblastr

mailblastr.api_key = "mb_xxxxxxxxx"

mailblastr.Emails.send({
  "from": "Acme <hello@yourdomain.com>",
  "to": [
    "user@example.com"
  ],
  "subject": "Your invoice",
  "html": "<p>Invoice attached.</p>",
  "attachments": [
    {
      "filename": "invoice.pdf",
      "path": "https://files.example.com/invoice.pdf"
    }
  ]
})
```

**Go**

```go
import "github.com/shekhu10/mailblastr-sdks/mailblastr-go"

client := mailblastr.NewClient("mb_xxxxxxxxx")

params := &mailblastr.SendEmailRequest{
    From:    "Acme <hello@yourdomain.com>",
    To:      []string{"delivered@example.com"},
    Subject: "hello world",
    Html:    "<p>it works!</p>",
}
sent, err := client.Emails.Send(params)
```

**Rust**

```rust
use mailblastr::{Mailblastr, CreateEmailBaseOptions};

let mb = Mailblastr::new("mb_xxxxxxxxx");

let email = CreateEmailBaseOptions::new(
    "Acme <hello@yourdomain.com>",
    ["delivered@example.com"],
    "hello world",
).with_html("<p>it works!</p>");
let _sent = mb.emails.send(email).await?;
```

**Java**

```java
import com.mailblastr.*;

Mailblastr mailblastr = new Mailblastr("mb_xxxxxxxxx");

SendEmailRequest request = SendEmailRequest.builder()
    .from("Acme <hello@yourdomain.com>")
    .to("delivered@example.com")
    .subject("hello world")
    .html("<p>it works!</p>")
    .build();
mailblastr.emails().send(request);
```

**.NET**

```csharp
using Mailblastr;

IMailblastr mailblastr = MailblastrClient.Create("mb_xxxxxxxxx");

var resp = await mailblastr.EmailSendAsync(new EmailMessage
{
    From = "Acme <hello@yourdomain.com>",
    To = "delivered@example.com",
    Subject = "hello world",
    HtmlBody = "<p>it works!</p>",
});
```

**cURL**

```bash
curl -X POST 'https://api.mailblastr.com/emails' \
  -H 'Authorization: Bearer mb_xxxxxxxxx' \
  -H 'Content-Type: application/json' \
  -d '{
  "from": "Acme <hello@yourdomain.com>",
  "to": ["user@example.com"],
  "subject": "Your invoice",
  "html": "<p>Invoice attached.</p>",
  "attachments": [
    { "filename": "invoice.pdf", "path": "https://files.example.com/invoice.pdf" }
  ]
}'
```

## Schedule for later

Pass an ISO 8601 `scheduled_at` to hold an email until a future time. It can be rescheduled or canceled while still pending. See [Schedule email](https://www.mailblastr.com/docs/emails/schedule).

**Node.js**

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

const mb = new MailBlastr('mb_xxxxxxxxx');

const { data, error } = await mb.emails.send({
  "from": "Acme <hello@yourdomain.com>",
  "to": ["user@example.com"],
  "subject": "Your weekly digest",
  "html": "<p>Here is what you missed.</p>",
  "scheduled_at": "2026-06-30T09:00:00Z"
});
console.log({ data, error });
```

**Ruby**

```ruby
require "mailblastr"

Mailblastr.api_key = "mb_xxxxxxxxx"

Mailblastr::Emails.send({
  "from": "Acme <hello@yourdomain.com>",
  "to": [
    "user@example.com"
  ],
  "subject": "Your weekly digest",
  "html": "<p>Here is what you missed.</p>",
  "scheduled_at": "2026-06-30T09:00:00Z"
})
```

**PHP**

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

$mailblastr->emails->send([
  'from' => "Acme <hello@yourdomain.com>",
  'to' => [
    "user@example.com"
  ],
  'subject' => "Your weekly digest",
  'html' => "<p>Here is what you missed.</p>",
  'scheduled_at' => "2026-06-30T09:00:00Z"
]);
```

**Python**

```python
import mailblastr

mailblastr.api_key = "mb_xxxxxxxxx"

mailblastr.Emails.send({
  "from": "Acme <hello@yourdomain.com>",
  "to": [
    "user@example.com"
  ],
  "subject": "Your weekly digest",
  "html": "<p>Here is what you missed.</p>",
  "scheduled_at": "2026-06-30T09:00:00Z"
})
```

**Go**

```go
import "github.com/shekhu10/mailblastr-sdks/mailblastr-go"

client := mailblastr.NewClient("mb_xxxxxxxxx")

params := &mailblastr.SendEmailRequest{
    From:    "Acme <hello@yourdomain.com>",
    To:      []string{"delivered@example.com"},
    Subject: "hello world",
    Html:    "<p>it works!</p>",
}
sent, err := client.Emails.Send(params)
```

**Rust**

```rust
use mailblastr::{Mailblastr, CreateEmailBaseOptions};

let mb = Mailblastr::new("mb_xxxxxxxxx");

let email = CreateEmailBaseOptions::new(
    "Acme <hello@yourdomain.com>",
    ["delivered@example.com"],
    "hello world",
).with_html("<p>it works!</p>");
let _sent = mb.emails.send(email).await?;
```

**Java**

```java
import com.mailblastr.*;

Mailblastr mailblastr = new Mailblastr("mb_xxxxxxxxx");

SendEmailRequest request = SendEmailRequest.builder()
    .from("Acme <hello@yourdomain.com>")
    .to("delivered@example.com")
    .subject("hello world")
    .html("<p>it works!</p>")
    .build();
mailblastr.emails().send(request);
```

**.NET**

```csharp
using Mailblastr;

IMailblastr mailblastr = MailblastrClient.Create("mb_xxxxxxxxx");

var resp = await mailblastr.EmailSendAsync(new EmailMessage
{
    From = "Acme <hello@yourdomain.com>",
    To = "delivered@example.com",
    Subject = "hello world",
    HtmlBody = "<p>it works!</p>",
});
```

**cURL**

```bash
curl -X POST 'https://api.mailblastr.com/emails' \
  -H 'Authorization: Bearer mb_xxxxxxxxx' \
  -H 'Content-Type: application/json' \
  -d '{
  "from": "Acme <hello@yourdomain.com>",
  "to": ["user@example.com"],
  "subject": "Your weekly digest",
  "html": "<p>Here is what you missed.</p>",
  "scheduled_at": "2026-06-30T09:00:00Z"
}'
```

**CLI**

```bash
mailblastr emails send \
  --from 'Acme <hello@yourdomain.com>' \
  --to 'user@example.com' \
  --subject 'Your weekly digest' \
  --html '<p>Here is what you missed.</p>' \
  --scheduled-at '2026-06-30T09:00:00Z'
```

## Send a batch

Deliver up to 100 distinct emails in one request by POSTing a JSON array to [POST /emails/batch](https://www.mailblastr.com/docs/api/emails-batch). Every item is validated before any email is sent. See [Batch sending](https://www.mailblastr.com/docs/emails/batch).

**Node.js**

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

const mb = new MailBlastr('mb_xxxxxxxxx');

const { data, error } = await mb.batch.send([
  { "from": "Acme <hello@yourdomain.com>", "to": ["a@example.com"], "subject": "Hi A", "html": "<p>Hello A</p>" },
  { "from": "Acme <hello@yourdomain.com>", "to": ["b@example.com"], "subject": "Hi B", "html": "<p>Hello B</p>" }
]);
console.log({ data, error });
```

**Ruby**

```ruby
require "mailblastr"

Mailblastr.api_key = "mb_xxxxxxxxx"

Mailblastr::Batch.send([
  {
    "from": "Acme <hello@yourdomain.com>",
    "to": [
      "a@example.com"
    ],
    "subject": "Hi A",
    "html": "<p>Hello A</p>"
  },
  {
    "from": "Acme <hello@yourdomain.com>",
    "to": [
      "b@example.com"
    ],
    "subject": "Hi B",
    "html": "<p>Hello B</p>"
  }
])
```

**PHP**

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

$mailblastr->batch->send([
  [
    'from' => "Acme <hello@yourdomain.com>",
    'to' => [
      "a@example.com"
    ],
    'subject' => "Hi A",
    'html' => "<p>Hello A</p>"
  ],
  [
    'from' => "Acme <hello@yourdomain.com>",
    'to' => [
      "b@example.com"
    ],
    'subject' => "Hi B",
    'html' => "<p>Hello B</p>"
  ]
]);
```

**Python**

```python
import mailblastr

mailblastr.api_key = "mb_xxxxxxxxx"

mailblastr.Batch.send([
  {
    "from": "Acme <hello@yourdomain.com>",
    "to": [
      "a@example.com"
    ],
    "subject": "Hi A",
    "html": "<p>Hello A</p>"
  },
  {
    "from": "Acme <hello@yourdomain.com>",
    "to": [
      "b@example.com"
    ],
    "subject": "Hi B",
    "html": "<p>Hello B</p>"
  }
])
```

**Go**

```go
package main

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

func main() {
    req, _ := http.NewRequest("POST", "https://api.mailblastr.com/emails/batch", strings.NewReader(`[
  { "from": "Acme <hello@yourdomain.com>", "to": ["a@example.com"], "subject": "Hi A", "html": "<p>Hello A</p>" },
  { "from": "Acme <hello@yourdomain.com>", "to": ["b@example.com"], "subject": "Hi B", "html": "<p>Hello B</p>" }
]`))
    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/batch")
        .header("Authorization", "Bearer mb_xxxxxxxxx")
        .header("Content-Type", "application/json")
        .body(r#"[
  { "from": "Acme <hello@yourdomain.com>", "to": ["a@example.com"], "subject": "Hi A", "html": "<p>Hello A</p>" },
  { "from": "Acme <hello@yourdomain.com>", "to": ["b@example.com"], "subject": "Hi B", "html": "<p>Hello B</p>" }
]"#)
        .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/batch"))
    .header("Authorization", "Bearer mb_xxxxxxxxx")
    .header("Content-Type", "application/json")
    .method("POST", HttpRequest.BodyPublishers.ofString("""
[
  { "from": "Acme <hello@yourdomain.com>", "to": ["a@example.com"], "subject": "Hi A", "html": "<p>Hello A</p>" },
  { "from": "Acme <hello@yourdomain.com>", "to": ["b@example.com"], "subject": "Hi B", "html": "<p>Hello B</p>" }
]
"""))
    .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/batch");
request.Headers.Add("Authorization", "Bearer mb_xxxxxxxxx");
request.Content = new StringContent(@"[
  { ""from"": ""Acme <hello@yourdomain.com>"", ""to"": [""a@example.com""], ""subject"": ""Hi A"", ""html"": ""<p>Hello A</p>"" },
  { ""from"": ""Acme <hello@yourdomain.com>"", ""to"": [""b@example.com""], ""subject"": ""Hi B"", ""html"": ""<p>Hello B</p>"" }
]", 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/batch' \
  -H 'Authorization: Bearer mb_xxxxxxxxx' \
  -H 'Content-Type: application/json' \
  -d '[
  { "from": "Acme <hello@yourdomain.com>", "to": ["a@example.com"], "subject": "Hi A", "html": "<p>Hello A</p>" },
  { "from": "Acme <hello@yourdomain.com>", "to": ["b@example.com"], "subject": "Hi B", "html": "<p>Hello B</p>" }
]'
```

**CLI**

```bash
mailblastr emails batch \
  --data '[{"from":"Acme <hello@yourdomain.com>","to":["a@example.com"],"subject":"Hi A","html":"<p>Hello A</p>"},{"from":"Acme <hello@yourdomain.com>","to":["b@example.com"],"subject":"Hi B","html":"<p>Hello B</p>"}]'
```

## Retry safely with an idempotency key

When a network blip leaves you unsure whether a send went through, retry with the same `Idempotency-Key` — MailBlastr processes it once and replays the original response. See [Idempotency keys](https://www.mailblastr.com/docs/emails/idempotency).

```bash
curl -X POST 'https://api.mailblastr.com/emails' \
  -H 'Authorization: Bearer mb_xxxxxxxxx' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: order-12345' \
  -d '{
    "from": "Acme <hello@yourdomain.com>",
    "to": ["user@example.com"],
    "subject": "Receipt",
    "html": "<p>Thanks!</p>"
  }'
```

## Add a contact to an audience

Grow a marketing list by creating a [contact](https://www.mailblastr.com/docs/audiences/contacts) inside an [audience](https://www.mailblastr.com/docs/audiences/overview). Contacts are the recipients of [campaigns](https://www.mailblastr.com/docs/campaigns/managing).

**Node.js**

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

const mb = new MailBlastr('mb_xxxxxxxxx');

const { data, error } = await mb.contacts.create({
  audienceId: 'aud_123',
  "email": "ada@example.com",
  "first_name": "Ada",
  "last_name": "Lovelace"
});
console.log({ data, error });
```

**Ruby**

```ruby
require 'net/http'
require 'uri'

uri = URI('https://api.mailblastr.com/audiences/aud_123/contacts')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Post.new(uri)
req['Authorization'] = 'Bearer mb_xxxxxxxxx'
req['Content-Type'] = 'application/json'
req.body = <<~JSON
{
  "email": "ada@example.com",
  "first_name": "Ada",
  "last_name": "Lovelace"
}
JSON
res = http.request(req)
puts res.body
```

**PHP**

```php
<?php
$ch = curl_init('https://api.mailblastr.com/audiences/aud_123/contacts');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer mb_xxxxxxxxx',
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => <<<'JSON'
{
  "email": "ada@example.com",
  "first_name": "Ada",
  "last_name": "Lovelace"
}
JSON,
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
```

**Python**

```python
import requests

res = requests.post(
    "https://api.mailblastr.com/audiences/aud_123/contacts",
    headers={"Authorization": "Bearer mb_xxxxxxxxx", "Content-Type": "application/json"},
    json={
  "email": "ada@example.com",
  "first_name": "Ada",
  "last_name": "Lovelace"
},
)
print(res.json())
```

**Go**

```go
package main

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

func main() {
    req, _ := http.NewRequest("POST", "https://api.mailblastr.com/audiences/aud_123/contacts", strings.NewReader(`{
  "email": "ada@example.com",
  "first_name": "Ada",
  "last_name": "Lovelace"
}`))
    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/audiences/aud_123/contacts")
        .header("Authorization", "Bearer mb_xxxxxxxxx")
        .header("Content-Type", "application/json")
        .body(r#"{
  "email": "ada@example.com",
  "first_name": "Ada",
  "last_name": "Lovelace"
}"#)
        .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/audiences/aud_123/contacts"))
    .header("Authorization", "Bearer mb_xxxxxxxxx")
    .header("Content-Type", "application/json")
    .method("POST", HttpRequest.BodyPublishers.ofString("""
{
  "email": "ada@example.com",
  "first_name": "Ada",
  "last_name": "Lovelace"
}
"""))
    .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/audiences/aud_123/contacts");
request.Headers.Add("Authorization", "Bearer mb_xxxxxxxxx");
request.Content = new StringContent(@"{
  ""email"": ""ada@example.com"",
  ""first_name"": ""Ada"",
  ""last_name"": ""Lovelace""
}", 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/audiences/aud_123/contacts' \
  -H 'Authorization: Bearer mb_xxxxxxxxx' \
  -H 'Content-Type: application/json' \
  -d '{
  "email": "ada@example.com",
  "first_name": "Ada",
  "last_name": "Lovelace"
}'
```

## Verify and handle a webhook

Subscribe to delivery events so your app reacts to bounces, complaints, opens, and clicks as they happen. Every payload is signed — verify the signature before trusting it. See [Webhooks](https://www.mailblastr.com/docs/webhooks/overview).

**Node.js**

```js
import { createHmac, timingSafeEqual } from 'node:crypto';

// Express handler — req.body is the raw request buffer
app.post('/webhooks/mailblastr', (req, res) => {
  const signature = req.header('MailBlastr-Signature');
  const expected = createHmac('sha256', process.env.MAILBLASTR_WEBHOOK_SECRET)
    .update(req.body) // raw bytes, not parsed JSON
    .digest('hex');

  const ok = signature && timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected),
  );
  if (!ok) return res.status(401).end();

  const event = JSON.parse(req.body.toString());
  if (event.type === 'email.bounced') {
    // the recipient was auto-suppressed — update your own records
  }
  res.status(200).end();
});
```

**Python**

```python
import hmac, hashlib, json
from flask import Flask, request, abort

app = Flask(__name__)
SECRET = "whsec_xxxxxxxxx".encode()

@app.post("/webhooks/mailblastr")
def handle():
    signature = request.headers.get("MailBlastr-Signature", "")
    expected = hmac.new(SECRET, request.get_data(), hashlib.sha256).hexdigest()
    if not hmac.compare_digest(signature, expected):
        abort(401)

    event = json.loads(request.get_data())
    if event["type"] == "email.bounced":
        pass  # recipient auto-suppressed; sync your records
    return "", 200
```

> **Note:** Always compute the signature over the **raw** request body. Re-serializing parsed JSON can reorder keys or change whitespace and break verification.

## More recipes

The same endpoints cover the full set of common email use-cases. Each is a plain HTTP request you can build in any language — no framework-specific package required.

| Use case | How |
| --- | --- |
| Basic send | POST a single email to [`/emails`](https://www.mailblastr.com/docs/api/emails-send) with `from`, `to`, `subject`, and `html` or `text`. |
| Batch send | POST a JSON array (up to 100) to [`/emails/batch`](https://www.mailblastr.com/docs/api/emails-batch). |
| Attachments | Add an `attachments` array with base64 `content` or a hosted `path` URL — see [Attachments](https://www.mailblastr.com/docs/emails/attachments). |
| Inline images (CID) | Reference an attachment from your HTML via `cid:` and set the attachment's `content_id` — see [Attachments](https://www.mailblastr.com/docs/emails/attachments). |
| Templates | Send a stored template by `template_id` with `template_variables` instead of inline `html` — see [Templates](https://www.mailblastr.com/docs/templates/overview). |
| Scheduling | Pass an ISO 8601 or natural-language `scheduled_at` to hold the email for later delivery — see [Schedule email](https://www.mailblastr.com/docs/emails/schedule). |
| Idempotency | Send an `Idempotency-Key` header to deduplicate retries — see [Idempotency keys](https://www.mailblastr.com/docs/emails/idempotency). |
| Contact form | Take form input on your backend and POST one (or a batch of) email(s) to MailBlastr. |
| Audiences & contacts | Create and manage list members under [`/audiences`](https://www.mailblastr.com/docs/audiences/overview) and their [contacts](https://www.mailblastr.com/docs/audiences/contacts). |
| Domains | Create and verify sending domains via [`/domains`](https://www.mailblastr.com/docs/domains/managing). |
| Double opt-in | On signup, send a confirmation email with a tokenized link; only add the [contact](https://www.mailblastr.com/docs/audiences/contacts) once they click it. |
| Webhooks | Subscribe to delivery events and verify each signed payload — see [Webhooks](https://www.mailblastr.com/docs/webhooks/overview). |
| Prevent threading (Gmail) | Vary the `subject` or set custom `headers` (e.g. a unique `X-Entity-Ref-ID`) so Gmail doesn't collapse messages into one thread. |

## Where to go next

- Browse the full [Send an email](https://www.mailblastr.com/docs/api/emails-send) reference for every body field (`cc`, `bcc`, `reply_to`, `headers`, `tags`).
- Set up a sending domain and DNS in [Domains](https://www.mailblastr.com/docs/domains/managing).
- Send marketing email to a list with [Campaigns](https://www.mailblastr.com/docs/campaigns/managing).
- See what is and isn't available yet in the [roadmap](https://www.mailblastr.com/docs/resources/sdks).
