# Campaign Follow-ups & Controls

> Engagement follow-ups, mailing-list To, and the unsubscribe policy on POST /campaigns.

`POST /campaigns`

Three optional controls extend a campaign beyond the base fields.

## Engagement follow-ups

Up to 5 `followups` send automatically after the campaign finishes — each fires `delay` later to the recipients matching its `condition`, threaded as a reply to their original email (same conversation; subject defaults to `Re: <campaign subject>`). Bodies support the same merge tags as the campaign.

| Field | Description |
| --- | --- |
| `condition` | One of `opened`, `clicked`, `not_opened`, `not_clicked`, `replied`, `not_replied`. |
| `delay` | Natural-language duration after the send completes, e.g. `"5 hours"`, `"4 days"` (max 30 days). |
| `subject` | Optional; defaults to `Re: <campaign subject>` to keep the thread. |
| `html` | The follow-up body (required). |

> **Note:** Open/click conditions require tracking to be enabled on the sending domain.

## Mailing-list To

Set `list_to: true` and every message shows a generated `recipient-<hex>@your-domain` address as the visible To header. Delivery is unchanged — each mail is still sent individually to its real recipient.

## Unsubscribe policy

| `unsubscribe_policy` | Behavior |
| --- | --- |
| `account` (default) | Any opt-out blocks the recipient — today's behavior. |
| `domain` | Only opt-outs recorded for THIS sending domain (plus account-wide ones) block. An unsubscribe from one of your other domains does not. |
| `ignore` | The unsubscribe list is skipped. Hard-bounced and complained addresses are ALWAYS excluded regardless. |

> **Warning:** Use `ignore` only where you have a lawful basis to email recipients who opted out.

## A/B winning metric

The `ab_test.metric` now accepts `reply` in addition to `open` and `click` — the winner is the variant with the higher reply rate (replies are matched from your inbound mail).

**Node.js**

```js
import { SendPing } from 'sendping';

const mb = new SendPing('mb_xxxxxxxxx');

const { data, error } = await mb.campaigns.create({
  "domain": "yourdomain.com", "from": "You <you@yourdomain.com>",
  "subject": "Big news", "html": "<p>Hi {{name}} …</p>",
  "list_to": true,
  "unsubscribe_policy": "domain",
  "ab_test": { "enabled": true, "subject_b": "Bigger news", "test_pct": 20, "metric": "reply" },
  "followups": [
    { "condition": "not_opened", "delay": "5 hours", "html": "<p>Bumping this…</p>" }
  ]
});
console.log({ data, error });
```

**Ruby**

```ruby
require "sendping"

SendPing.api_key = "mb_xxxxxxxxx"

SendPing::Campaigns.create({
  "domain": "yourdomain.com",
  "from": "You <you@yourdomain.com>",
  "subject": "Big news",
  "html": "<p>Hi {{name}} …</p>",
  "list_to": true,
  "unsubscribe_policy": "domain",
  "ab_test": {
    "enabled": true,
    "subject_b": "Bigger news",
    "test_pct": 20,
    "metric": "reply"
  },
  "followups": [
    {
      "condition": "not_opened",
      "delay": "5 hours",
      "html": "<p>Bumping this…</p>"
    }
  ]
})
```

**PHP**

```php
<?php
require 'vendor/autoload.php';

use SendPing\SendPing;

$sendping = SendPing::client('mb_xxxxxxxxx');

$sendping->campaigns->create([
  'domain' => "yourdomain.com",
  'from' => "You <you@yourdomain.com>",
  'subject' => "Big news",
  'html' => "<p>Hi {{name}} …</p>",
  'list_to' => true,
  'unsubscribe_policy' => "domain",
  'ab_test' => [
    'enabled' => true,
    'subject_b' => "Bigger news",
    'test_pct' => 20,
    'metric' => "reply"
  ],
  'followups' => [
    [
      'condition' => "not_opened",
      'delay' => "5 hours",
      'html' => "<p>Bumping this…</p>"
    ]
  ]
]);
```

**Python**

```python
import sendping

sendping.api_key = "mb_xxxxxxxxx"

sendping.Campaigns.create({
  "domain": "yourdomain.com",
  "from": "You <you@yourdomain.com>",
  "subject": "Big news",
  "html": "<p>Hi {{name}} …</p>",
  "list_to": True,
  "unsubscribe_policy": "domain",
  "ab_test": {
    "enabled": True,
    "subject_b": "Bigger news",
    "test_pct": 20,
    "metric": "reply"
  },
  "followups": [
    {
      "condition": "not_opened",
      "delay": "5 hours",
      "html": "<p>Bumping this…</p>"
    }
  ]
})
```

**Go**

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

client := sendping.NewClient("mb_xxxxxxxxx")

campaign, err := client.Campaigns.Create(&sendping.CreateCampaignRequest{
    Domain:            "yourdomain.com",
    From:              "You <you@yourdomain.com>",
    Subject:           "Big news",
    Html:              "<p>Hi {{name}} …</p>",
    ListTo:            true,
    UnsubscribePolicy: "domain",
    AbTest: &sendping.CampaignAbTest{
        Enabled:  true,
        SubjectB: "Bigger news",
        TestPct:  20,
        Metric:   "reply",
    },
    Followups: []sendping.CampaignFollowupInput{
        {
            Condition: "not_opened",
            Delay:     "5 hours",
            Html:      "<p>Bumping this…</p>",
        },
    },
})
```

**Rust**

```rust
use sendping::{AbMetric, CampaignAbTestOptions, CampaignFollowup, CreateCampaignOptions, FollowupCondition, SendPing, UnsubscribePolicy};

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

let params = CreateCampaignOptions::new(
    "yourdomain.com",
    "You <you@yourdomain.com>",
    "Big news",
)
.with_html("<p>Hi {{name}} …</p>")
.with_list_to(true)
.with_unsubscribe_policy(UnsubscribePolicy::Domain)
.with_ab_test(CampaignAbTestOptions::enabled()
        .with_subject_b("Bigger news")
        .with_test_pct(20)
        .with_metric(AbMetric::Reply))
.with_followup(CampaignFollowup::new(
        FollowupCondition::NotOpened,
        "5 hours",
        "<p>Bumping this…</p>",
    ));
let _campaign = mb.campaigns.create(params).await?;
```

**Java**

```java
import co.sendping.SendPing;
import co.sendping.SendPingResponse;
import co.sendping.requests.CampaignAbTest;
import co.sendping.requests.CampaignFollowup;
import co.sendping.requests.CreateCampaignRequest;

SendPing sendping = new SendPing("mb_xxxxxxxxx");

CreateCampaignRequest request = CreateCampaignRequest.builder()
        .domain("yourdomain.com")
        .from("You <you@yourdomain.com>")
        .subject("Big news")
        .html("<p>Hi {{name}} …</p>")
        .listTo(true)
        .unsubscribePolicy("domain")
        .abTest(CampaignAbTest.builder()
                .enabled(true)
                .subjectB("Bigger news")
                .testPct(20)
                .metric("reply")
                .build())
        .followup(CampaignFollowup.builder()
                .condition("not_opened")
                .delay("5 hours")
                .html("<p>Bumping this…</p>")
                .build())
        .build();

SendPingResponse response = sendping.campaigns().create(request);
```

**.NET**

```csharp
using SendPing;

ISendPing sendping = SendPingClient.Create("mb_xxxxxxxxx");

var resp = await sendping.CampaignCreateAsync(new CampaignCreateOptions
{
    Domain = "yourdomain.com",
    From = "You <you@yourdomain.com>",
    Subject = "Big news",
    HtmlBody = "<p>Hi {{name}} …</p>",
    ListTo = true,
    UnsubscribePolicy = "domain",
    AbTest = new CampaignAbTest
    {
        Enabled = true,
        SubjectB = "Bigger news",
        TestPct = 20,
        Metric = "reply",
    },
    Followups = new List<CampaignFollowup>
    {
        new()
        {
            Condition = "not_opened",
            Delay = "5 hours",
            HtmlBody = "<p>Bumping this…</p>",
        },
    },
});
```

**cURL**

```bash
curl -X POST 'https://www.sendping.co/api/campaigns' \
  -H 'Authorization: Bearer mb_xxxxxxxxx' \
  -H 'Content-Type: application/json' \
  -d '{
  "domain": "yourdomain.com", "from": "You <you@yourdomain.com>",
  "subject": "Big news", "html": "<p>Hi {{name}} …</p>",
  "list_to": true,
  "unsubscribe_policy": "domain",
  "ab_test": { "enabled": true, "subject_b": "Bigger news", "test_pct": 20, "metric": "reply" },
  "followups": [
    { "condition": "not_opened", "delay": "5 hours", "html": "<p>Bumping this…</p>" }
  ]
}'
```

**CLI**

```bash
sendping campaigns create \
  --domain 'yourdomain.com' \
  --from 'You <you@yourdomain.com>' \
  --subject 'Big news' \
  --html '<p>Hi {{name}} …</p>' \
  --list-to \
  --unsubscribe-policy 'domain' \
  --ab-test '{"enabled":true,"subject_b":"Bigger news","test_pct":20,"metric":"reply"}' \
  --followups '[{"condition":"not_opened","delay":"5 hours","html":"<p>Bumping this…</p>"}]'
```
