[Cotlet](https://cotlet.dev/index.md) · [Integrations](https://cotlet.dev/integrations.md) · [How it works](https://cotlet.dev/how-it-works.md) · [Use cases](https://cotlet.dev/use-cases.md) · [Security](https://cotlet.dev/security.md) · [For developers](https://cotlet.dev/for-developers.md) · [For automation agencies](https://cotlet.dev/for-agencies.md) · [Blog](https://cotlet.dev/blog.md) · [API docs](https://cotlet.dev/docs.md) · [Help center](https://cotlet.dev/help.md) · [Changelog](https://cotlet.dev/changelog.md) · [Contact](https://cotlet.dev/contact.md) · [Pricing](https://cotlet.dev/pricing.md) · [Sign up](https://cotlet.dev/signup)

# EmailOctopus API and MCP server

> EmailOctopus has a public REST API (v2) for lists, contacts, fields, tags, campaign reports and starting an automation for a contact, but no official MCP server and no API for creating, scheduling or sending a campaign (checked 20 Oct 2026). EmailOctopus states that it does not support API sending: all emails need to be created directly in the Dashboard.

Email marketing platform for newsletters and campaigns: lists with tags and fields, a drag and drop editor, segments, automations, forms and campaign reports.

## What is the EmailOctopus API?

Cotlet's EmailOctopus API exposes 14 endpoints for your own EmailOctopus account: list lists, list contacts, list segments, list campaigns, get campaign report, list campaign activity, create segment, duplicate campaign, update campaign, set campaign recipients, schedule campaign, send campaign, unschedule campaign and unsubscribe contacts. The list_lists endpoint returns lists of your EmailOctopus account with their subscribed, pending and unsubscribed counts. Each endpoint takes simple JSON inputs like campaign_id, list_id or tag and works both as an operation of the emailoctopus_read or emailoctopus_write MCP tool for agents and as a REST call for scripts.

- **Category:** [Marketing & SEO](https://cotlet.dev/integrations/category/marketing-seo.md)
- **Endpoints:** 14 (6 read, 8 write)
- **Updated:** 2026-10-22

EmailOctopus has a public REST API (v2) for lists, contacts, fields, tags, campaign reports and starting an automation for a contact, but no official MCP server and no API for creating, scheduling or sending a campaign (checked 20 Oct 2026). Cotlet is a hosted MCP server and REST API for EmailOctopus with 14 endpoints (6 read, 8 write): you sign in once in your own cloud browser, your AI agent does the work.

## Does EmailOctopus have an official API?

EmailOctopus has a public REST API (v2) for lists, contacts, fields, tags, campaign reports and starting an automation for a contact, but no official MCP server and no API for creating, scheduling or sending a campaign (checked 20 Oct 2026). EmailOctopus states that it does not support API sending: all emails need to be created directly in the Dashboard.

| Task | EmailOctopus official | Cotlet |
|---|---|---|
| List lists and contacts, filtered by status or tag | Yes: API v2, 100 results a page, 10 requests a second | Yes |
| Read a campaign report and the contacts behind each count | Yes: API v2: summary, links and per-contact reports by status | Yes |
| Unsubscribe contacts | Partly: API v2 sets a contact status one by one or in a batch, but cannot read segments, so you pick the contacts yourself | Yes |
| Create a segment | No: Segments exist only in the Dashboard | Yes |
| Duplicate a campaign and change its name, subject or sender | No: The API reads campaigns only | Yes |
| Choose who a campaign goes to: list, segment or tag | No | Yes |
| Schedule, unschedule or send a campaign | No: EmailOctopus does not support API sending | Yes |
| Find campaigns by status: draft, scheduled or sent | Partly: API v2 lists campaigns with their status, but no scheduled status or search by name or subject | Yes |

Sources: [EmailOctopus API v2 documentation](https://emailoctopus.com/api-documentation/v2), [EmailOctopus Help: API limits](https://help.emailoctopus.com/article/91-api-limits), [EmailOctopus Help: Using Zapier to integrate with other web services](https://help.emailoctopus.com/article/197-using-zapier-to-integrate-with-other-web-services), [EmailOctopus Help: Using Make to integrate with other web services](https://help.emailoctopus.com/article/212-make-integration)

## For AI agents

```text
EmailOctopus has a public REST API (v2) for lists, contacts, fields, tags, campaign reports and starting an automation for a contact, but no official MCP server and no API for creating, scheduling or sending a campaign (checked 20 Oct 2026). EmailOctopus states that it does not support API sending: all emails need to be created directly in the Dashboard.
Cotlet provides a hosted MCP server and REST API for EmailOctopus: 14 tools (6 read, 8 write).
Access       Sign up at https://cotlet.dev/app/signup?app=emailoctopus, then request the app and create API keys in the Cotlet console.

MCP server   https://cotlet.dev/mcp/v1
MCP tools    emailoctopus_read, emailoctopus_write, reads and writes apart; call one with {"operation": "<operation>", "arguments": {...}}
REST base    https://cotlet.dev/api/v1/emailoctopus, each operation at its own route, e.g. POST /api/v1/emailoctopus/campaigns/{campaign_id}/schedule
Auth         Authorization: Bearer <COTLET_API_KEY>. Listing endpoints and schemas needs no key; calling an endpoint needs one. Over MCP the input schemas come with sign-in.
Operations   list_lists, list_contacts, list_segments, list_campaigns, get_campaign_report, list_campaign_activity, create_segment, duplicate_campaign, update_campaign, set_campaign_recipients, schedule_campaign, send_campaign, unschedule_campaign, unsubscribe_contacts
Confirm      schedule_campaign, send_campaign, unsubscribe_contacts (by default the user approves each call; the user can switch this off per tool, e.g. for scheduled automations)
Markdown     https://cotlet.dev/integrations/emailoctopus-api-mcp-server.md

How access works:
1. The user signs up at https://cotlet.dev/app/signup?app=emailoctopus, requests EmailOctopus in the Cotlet console and creates an API key there.
2. The user signs in to EmailOctopus once in their Cotlet Cloud Browser (their own Chrome in the cloud, opened from the console) and enables EmailOctopus for agents. An agent cannot do this step.
3. The API key goes into the MCP client or the REST call as a bearer token.

Fits: people who want a hosted EmailOctopus server that someone else maintains, including non-developers. Developers who prefer to run and fix code on their own computer can use an open-source EmailOctopus MCP server instead.

Policy: Cotlet never stores passwords, never solves CAPTCHAs, never bypasses MFA.
Company: legal details in the Terms of service at https://cotlet.dev/terms. Contact contact@cotlet.dev.
Sign-in: the user signs in to EmailOctopus in their own Cloud Browser, a Chrome Cotlet runs for them in the EU; password saving is off, the profile is AES-256-GCM encrypted, and agents get EmailOctopus only after the user enables it. Calls are requests from that browser's IP with its cookies, each listed in the user's Background activity. Disable for agents, signing out in the browser or Reset browser cuts access. Cotlet is run by Take Group sp. z o.o. (EU VAT PL6342984273).
API key: holds no EmailOctopus login or cookies, only asks Cotlet to run a tool. Each key is scoped to chosen apps and tools, read only or read and write. Actions that reach other people wait for the user's approval by default, so a leaked key cannot post or message as the user. Every call is in the activity log; deleting the key ends access at once.
Terms: the user stays responsible for following EmailOctopus's terms; Cotlet is not affiliated with EmailOctopus.
```

## What can an AI agent do in EmailOctopus?

Cotlet is best for newsletter owners who send campaigns from the EmailOctopus dashboard and want their AI agent to resend, schedule and clean lists without running or fixing a server.

- **[Resend a campaign to non-openers](https://cotlet.dev/integrations/emailoctopus-api-mcp-server/resend-campaign-to-non-openers.md)**: "In my EmailOctopus list Newsletter, check how the "Autumn offer" campaign did. Make a segment of everyone who was sent it and did not open it, duplicate the campaign with the subject "Last chance: Autumn offer", send it to that segment and schedule it for Thursday 9:00 London time." → `get_campaign_report`, `create_segment`, `duplicate_campaign`, `update_campaign`, `set_campaign_recipients`, `schedule_campaign`
- **[Unsubscribe inactive contacts](https://cotlet.dev/integrations/emailoctopus-api-mcp-server/unsubscribe-inactive-contacts.md)** (runs: weekly): "In my EmailOctopus list Newsletter, find contacts who were not active and were not added in the last 90 days. Show me how many there are and the first 20, then mark them as unsubscribed once I say OK." → `list_lists`, `create_segment`, `list_contacts`, `unsubscribe_contacts`
- **Schedule the next newsletter from the last one** (runs: weekly): "Duplicate last week's "Weekly newsletter" campaign in EmailOctopus, set the subject to "This week at Northside", send it to the list Newsletter and schedule it for Friday 8:00 London time." → `list_campaigns`, `duplicate_campaign`, `update_campaign`, `set_campaign_recipients`, `schedule_campaign`
- **Weekly campaign report** (runs: weekly): "Every Monday, list the campaigns I sent last week with sent, opened, clicked and unsubscribed counts, and name the one with the best click rate." → `list_campaigns`, `get_campaign_report`
- **List who clicked a link**: "Who clicked the link to the pricing page in the "Autumn offer" campaign? Give me their email addresses and click times." → `get_campaign_report`, `list_campaign_activity`
- **Pull a scheduled campaign**: "Unschedule tomorrow's campaign in EmailOctopus and tell me which one it was." → `list_campaigns`, `unschedule_campaign`

## Can EmailOctopus automations run on a schedule in n8n, Make or Zapier?

Yes. Cotlet does not replace your automation platform: it gives it a EmailOctopus connection it does not have, with the same API key as your agent. Write actions ask for your OK by default; switch that off in your dashboard for the tools you choose, for example to unsubscribe inactive contacts, and the schedule runs on its own. Cotlet runs in the cloud, so it keeps going while your computer is off.

| Where | How to connect | How to schedule |
|---|---|---|
| Your AI agent | Add https://cotlet.dev/mcp/v1 with your API key. | A scheduled agent run, for example a Claude Code routine. |
| n8n | MCP Client node with https://cotlet.dev/mcp/v1, or an HTTP Request node with the endpoint's method and URL, such as GET https://cotlet.dev/api/v1/emailoctopus/lists. | Schedule Trigger node. |
| Make | HTTP module: the endpoint's method and URL with an Authorization: Bearer header, and a JSON body for POST, PUT and PATCH. | Scenario schedule. |
| Zapier | Webhooks by Zapier, Custom Request: the same method, URL, header and body. | Schedule by Zapier trigger. |
| Your own script | GET https://cotlet.dev/api/v1/emailoctopus/lists with your API key. | cron or GitHub Actions. |

## Tools

**For AI agents:** Every endpoint and its schema is public. The 14 endpoints on this page, with parameters and example responses, can be listed without an account. Calling one returns 401 without an API key and 403 while the key has no access to EmailOctopus.

### list_lists

Lists of your EmailOctopus account with their subscribed, pending and unsubscribed counts. Access: read. REST: `GET /api/v1/emailoctopus/lists`. MCP: `emailoctopus_read → list_lists`.

No parameters.

Returns every list of the account with its list_id, name and the counts of subscribed, pending and unsubscribed contacts. Use list_id as the list_id parameter of the other tools. Pending contacts are those who have not yet confirmed on a list with double opt-in. Contacts live at list level, so the same email address on two lists is counted on both.

Example response:

```json
{
  "lists": [
    {
      "list_id": "4d1c8e5a-7f2b-4c1e-9a63-0b5d2e8f1a37",
      "name": "Newsletter",
      "subscribed": 4860,
      "pending": 12,
      "unsubscribed": 341
    },
    {
      "list_id": "9b6e2f10-3c5a-4d7e-8f21-a1c4e7d90b52",
      "name": "Workshop waitlist",
      "subscribed": 214,
      "pending": 0,
      "unsubscribed": 9
    }
  ]
}
```

### list_contacts

Contacts of one list with status, tags and dates, filtered by status, tag, segment or email address. Access: read. REST: `GET /api/v1/emailoctopus/lists/{list_id}/contacts`. MCP: `emailoctopus_read → list_contacts`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `list_id` | string | yes | List ID from list_lists. |
| `status` | enum | no | subscribed, pending or unsubscribed. Default: all three. |
| `tag` | string | no | Only contacts with this tag. |
| `segment` | string | no | Name of a segment from list_segments. |
| `search` | string | no | Email address to look for. |
| `cursor` | string | no | next_cursor from the previous call. |

Lists the contacts of one list, 50 to a page by default; pass next_cursor back as cursor for the next page. status picks the subscribed, pending or unsubscribed filter of the contacts page. tag and segment filter the way the Tags and Segment drop-downs do, and search matches an email address. The response also returns total, the number of contacts that match the filters. added is when the contact joined the list, last_changed when it was last edited.

Example response:

```json
{
  "total": 212,
  "contacts": [
    {
      "contact_id": "e3ab8c80-5f65-11ed-835e-030e4bb63150",
      "email_address": "sam@example.com",
      "first_name": "Sam",
      "last_name": "Reed",
      "tags": [
        "customer"
      ],
      "status": "subscribed",
      "added": "2025-03-04T10:12:00Z",
      "last_changed": "2025-03-04T10:12:00Z"
    },
    {
      "contact_id": "f1c2d3e4-6a7b-11ed-9c8d-0242ac120002",
      "email_address": "lena@example.org",
      "first_name": "Lena",
      "last_name": "Novak",
      "tags": [],
      "status": "subscribed",
      "added": "2025-04-18T16:40:00Z",
      "last_changed": "2025-06-02T09:05:00Z"
    }
  ],
  "next_cursor": "2"
}
```

### list_segments

Saved segments of a list with the conditions each one is built from. Access: read. REST: `GET /api/v1/emailoctopus/lists/{list_id}/segments`. MCP: `emailoctopus_read → list_segments`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `list_id` | string | yes | List ID from list_lists. |

Returns the reusable segments shown on the Segments tab of the Contacts page: name, match type (all, any or none) and the conditions in the words of the segment editor. Use a segment name as the segment parameter of list_contacts, set_campaign_recipients and unsubscribe_contacts. One-off segments built inside a campaign are not saved, so they do not appear.

Example response:

```json
{
  "segments": [
    {
      "name": "Clicked in last 90 days",
      "match": "all",
      "conditions": [
        "Campaign activity: clicked, any campaign within the last 90 days"
      ]
    },
    {
      "name": "Did not open: Autumn offer",
      "match": "all",
      "conditions": [
        "Campaign activity: did not open, Autumn offer",
        "Campaign activity: was sent, Autumn offer"
      ]
    }
  ]
}
```

### list_campaigns

Campaigns with status, subject, list, how many contacts they were sent to and open and click rates. Access: read. REST: `GET /api/v1/emailoctopus/campaigns`. MCP: `emailoctopus_read → list_campaigns`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `status` | enum | no | all, sent, scheduled or draft. Default: all. |
| `search` | string | no | Text in the campaign name or subject; name: or subject: limits the search. |
| `sort` | enum | no | date, name, open_rate, click_rate or sent. Default: date. |
| `order` | enum | no | asc or desc. Default: desc. |
| `cursor` | string | no | next_cursor from the previous call. |

Returns campaigns the way the Campaigns tab lists them, newest first unless you sort. status filters to sent, scheduled or draft. search matches the campaign name or subject; prefix a term with name: or subject: to search one of them. sort is name, date, open_rate, click_rate or sent. date is the day the campaign was sent, or scheduled for, or created for a draft. Pass next_cursor back as cursor for the next page.

Example response:

```json
{
  "campaigns": [
    {
      "campaign_id": "c7a41b92-0d3e-4f58-b6a1-2e9d8c5f7014",
      "name": "Autumn offer",
      "subject": "Autumn offer: 20% off the new menu",
      "status": "sent",
      "list": "Newsletter",
      "sent_to": 1840,
      "open_rate": 38.2,
      "click_rate": 5.2,
      "date": "2026-10-14"
    },
    {
      "campaign_id": "a2f9d6e3-81b4-4c07-9e5a-7d1c3b8f2e60",
      "name": "Weekly newsletter",
      "subject": "This week at Northside",
      "status": "scheduled",
      "list": "Newsletter",
      "sent_to": null,
      "open_rate": null,
      "click_rate": null,
      "date": "2026-10-23"
    }
  ],
  "next_cursor": null
}
```

### get_campaign_report

Report of one sent campaign: sent, opened, clicked, unsubscribed, bounced and complained, plus links clicked. Access: read. REST: `GET /api/v1/emailoctopus/campaigns/{campaign_id}/report`. MCP: `emailoctopus_read → get_campaign_report`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `campaign_id` | string | yes | Campaign ID from list_campaigns. |

Returns the counts and rates of the report on the Reports tab: sent, opened, clicked, unsubscribed, hard and soft bounces, complained, and each tracked link with its unique and total clicks. A report appears within minutes of sending, at busy times after up to a couple of hours, so a campaign that is still sending returns a notice instead of numbers. Links with a merge tag or custom field in the address are not tracked. On the free Starter plan reports stay available for 30 days.

Example response:

```json
{
  "campaign_id": "c7a41b92-0d3e-4f58-b6a1-2e9d8c5f7014",
  "name": "Autumn offer",
  "sent": 1840,
  "opened": 702,
  "open_rate": 38.2,
  "clicked": 96,
  "click_rate": 5.2,
  "unsubscribed": 9,
  "bounced": {
    "hard": 14,
    "soft": 22
  },
  "complained": 1,
  "links": [
    {
      "url": "https://northside.example/menu",
      "unique_clicks": 71,
      "total_clicks": 88
    },
    {
      "url": "https://northside.example/pricing",
      "unique_clicks": 25,
      "total_clicks": 31
    }
  ]
}
```

### list_campaign_activity

Contacts who opened, clicked, unsubscribed, bounced or complained on a campaign, or did not open or click. Access: read. REST: `GET /api/v1/emailoctopus/campaign-activities`. MCP: `emailoctopus_read → list_campaign_activity`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `campaign_id` | string | yes | Campaign ID from list_campaigns. |
| `activity` | enum | yes | opened, clicked, unsubscribed, bounced, complained, did_not_open or did_not_click. |
| `link` | string | no | A tracked link from get_campaign_report; only with activity clicked. |
| `cursor` | string | no | next_cursor from the previous call. |

Returns the contacts behind one count of a campaign report, 100 to a page; pass next_cursor back as cursor. activity picks the report: opened, clicked, unsubscribed, bounced, complained, did_not_open or did_not_click. With activity clicked, link limits the list to one tracked link. time is the first interaction in UTC and count the number of interactions. A contact deleted since the send has a blank email address but keeps its activity. did_not_open can include contacts who were not sent the campaign and, because Apple Mail pre-fetches the tracking pixel, people who never read it.

Example response:

```json
{
  "activity": "clicked",
  "contacts": [
    {
      "contact_id": "e3ab8c80-5f65-11ed-835e-030e4bb63150",
      "email_address": "sam@example.com",
      "time": "2026-10-14T08:12:00Z",
      "count": 2,
      "subscribed": true
    },
    {
      "contact_id": "f1c2d3e4-6a7b-11ed-9c8d-0242ac120002",
      "email_address": "lena@example.org",
      "time": "2026-10-14T11:47:00Z",
      "count": 1,
      "subscribed": true
    }
  ],
  "next_cursor": null
}
```

### create_segment

Create a reusable segment on a list from conditions on tags, fields, dates, source or campaign and contact activity. Access: write. REST: `POST /api/v1/emailoctopus/lists/{list_id}/segments`. MCP: `emailoctopus_write → create_segment`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `list_id` | string | yes | List ID from list_lists. |
| `name` | string | yes | Name of the segment. |
| `match` | enum | yes | all, any or none of the conditions must match. |
| `conditions` | array | yes | Objects with type, operator and value. type: first_name, last_name, field, date_created, last_updated, source, segment, campaign_activity, contact_activity or tag. |

Saves a segment on the Segments tab of the Contacts page and returns it. match is all, any or none, as in the segment editor. Each condition has a type, an operator in the words of the editor (for example "did not open", "was sent", "active or added within") and a value such as a campaign name, a tag or a number of days. Contact activity looks back at most 365 days. The segment holds no email by itself, so creating it reaches no one; it only changes who a later campaign or bulk action can pick.

Example response:

```json
{
  "segment": "Did not open: Autumn offer",
  "list_id": "4d1c8e5a-7f2b-4c1e-9a63-0b5d2e8f1a37",
  "match": "all",
  "conditions": [
    "Campaign activity: did not open, Autumn offer",
    "Campaign activity: was sent, Autumn offer"
  ],
  "created": true
}
```

### duplicate_campaign

Make a draft copy of a campaign, like Duplicate in the Campaigns tab. Access: write. REST: `POST /api/v1/emailoctopus/campaigns/{campaign_id}/duplicate`. MCP: `emailoctopus_write → duplicate_campaign`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `campaign_id` | string | yes | Campaign ID from list_campaigns. |

Does what Duplicate in the campaign drop-down does: it starts a new campaign from an existing one, sent or draft, and returns the new campaign_id. The copy is a draft and reaches no one until schedule_campaign or send_campaign runs, so this tool needs no confirmation. Change the name, subject or sender with update_campaign, and the recipients with set_campaign_recipients.

Example response:

```json
{
  "campaign_id": "d5e8a3b1-62c9-4e70-8a14-9f0b7c2d6e83",
  "name": "Autumn offer, last chance",
  "status": "draft",
  "copied_from": "c7a41b92-0d3e-4f58-b6a1-2e9d8c5f7014"
}
```

### update_campaign

Change the name, subject, preview text or sender of a draft campaign. Access: write. REST: `PATCH /api/v1/emailoctopus/campaigns/{campaign_id}`. MCP: `emailoctopus_write → update_campaign`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `campaign_id` | string | yes | Campaign ID from list_campaigns. |
| `name` | string | no | Internal name of the campaign; subscribers do not see it. |
| `subject` | string | no | Subject line. |
| `preview_text` | string | no | Preview text shown after the subject. |
| `from_name` | string | no | Sender name. |
| `from_email` | string | no | Sender email address verified in your account. |

Edits the set-up fields of a campaign that has not been sent: name, subject, preview text (the line shown after the subject in the inbox), sender name and sender email address. Fields you leave out stay as they are. The tool does not touch the design or the HTML of the email. It reaches no one, so it needs no confirmation.

Example response:

```json
{
  "campaign_id": "d5e8a3b1-62c9-4e70-8a14-9f0b7c2d6e83",
  "name": "Autumn offer, last chance",
  "subject": "Last chance: Autumn offer",
  "preview_text": "Ends Sunday",
  "from_name": "Northside Bakery",
  "from_email": "hello@northside.example",
  "status": "draft"
}
```

### set_campaign_recipients

Choose who a draft campaign goes to: a whole list, a saved segment or a tag. Access: write. REST: `PUT /api/v1/emailoctopus/lists/{list_id}/campaigns/{campaign_id}/recipients`. MCP: `emailoctopus_write → set_campaign_recipients`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `campaign_id` | string | yes | Campaign ID from list_campaigns. |
| `audience` | enum | yes | list, segment or tag. |
| `list_id` | string | yes | List ID from list_lists. |
| `segment` | string | no | Segment name from list_segments; with audience segment. |
| `tag` | string | no | Tag name; with audience tag. |

Fills the "Sending to" field of a draft campaign. audience is list, segment or tag. A campaign goes to one list at a time, so list_id is required and segment or tag is a filter inside it. For a scheduled campaign, a segment or tag is checked right before sending, so contacts added or removed after scheduling are counted at that moment. The tool only sets the audience and reaches no one.

Example response:

```json
{
  "campaign_id": "d5e8a3b1-62c9-4e70-8a14-9f0b7c2d6e83",
  "audience": "segment",
  "list": "Newsletter",
  "segment": "Did not open: Autumn offer",
  "status": "draft"
}
```

### schedule_campaign

Schedule a draft campaign for a date, time and timezone. Access: write, asks the user first. REST: `POST /api/v1/emailoctopus/campaigns/{campaign_id}/schedule`. MCP: `emailoctopus_write → schedule_campaign`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `campaign_id` | string | yes | Campaign ID from list_campaigns. |
| `date` | date | yes | Sending date, YYYY-MM-DD. |
| `time` | string | yes | Sending time, HH:MM, 24-hour. |
| `timezone` | string | yes | Timezone name, for example Europe/London. |

Does what the Schedule button does: it sets the sending date, time and timezone and returns the scheduled time. The campaign must have a subject, a sender, a design and recipients, and the account must be allowed to send. Once scheduled it goes to your contacts at that time unless you call unschedule_campaign first. By default you confirm each call; you can switch that off for this tool.

Example response:

```json
{
  "campaign_id": "d5e8a3b1-62c9-4e70-8a14-9f0b7c2d6e83",
  "name": "Autumn offer, last chance",
  "status": "scheduled",
  "scheduled_for": "2026-10-22T09:00:00+01:00",
  "timezone": "Europe/London"
}
```

### send_campaign

Send a draft campaign right away. Access: write, asks the user first. REST: `POST /api/v1/emailoctopus/campaigns/{campaign_id}`. MCP: `emailoctopus_write → send_campaign`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `campaign_id` | string | yes | Campaign ID from list_campaigns. |

Sends the campaign now to its recipients, like choosing to send it right away instead of scheduling it. It cannot be recalled once sending starts. The agent should read the recipients with list_campaigns first and check them with you. By default you confirm each call; you can switch that off for this tool.

Example response:

```json
{
  "campaign_id": "d5e8a3b1-62c9-4e70-8a14-9f0b7c2d6e83",
  "name": "Autumn offer, last chance",
  "status": "sending",
  "sent_at": "2026-10-20T14:05:00Z"
}
```

### unschedule_campaign

Stop a scheduled campaign from sending, like Unschedule in the Campaigns tab. Access: write. REST: `POST /api/v1/emailoctopus/campaigns/{campaign_id}/unschedule`. MCP: `emailoctopus_write → unschedule_campaign`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `campaign_id` | string | yes | Campaign ID from list_campaigns. |

Picks Unschedule from the campaign drop-down, so the campaign no longer goes out at its scheduled time. It reaches no one and is undone by calling schedule_campaign again, so this tool needs no confirmation. Campaigns that are already sending or sent are not affected.

Example response:

```json
{
  "campaign_id": "a2f9d6e3-81b4-4c07-9e5a-7d1c3b8f2e60",
  "name": "Weekly newsletter",
  "scheduled": false
}
```

### unsubscribe_contacts

Mark contacts as unsubscribed in bulk, by segment, tag or email addresses. Access: write, asks the user first. REST: `POST /api/v1/emailoctopus/lists/{list_id}/contacts/unsubscribe`. MCP: `emailoctopus_write → unsubscribe_contacts`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `list_id` | string | yes | List ID from list_lists. |
| `segment` | string | no | Segment name from list_segments. |
| `tag` | string | no | Unsubscribe the contacts with this tag. |
| `emails` | array | no | Email addresses to unsubscribe. |

Does what Actions, then Mark as unsubscribed, does on the contacts page. Give exactly one of segment, tag or emails. Unsubscribed contacts stay in the list and stop counting towards your plan's subscriber limit; the tool never deletes a contact. An unsubscribed contact cannot be re-subscribed through an import. It returns how many contacts changed. By default you confirm each call; you can switch that off for this tool.

Example response:

```json
{
  "list_id": "4d1c8e5a-7f2b-4c1e-9a63-0b5d2e8f1a37",
  "segment": "Inactive for 90 days",
  "unsubscribed": 212
}
```

## How do I connect EmailOctopus to Claude Code, Codex or Cursor?

Connecting EmailOctopus takes three steps: sign up, sign in to EmailOctopus once in your Cloud Browser and enable it for agents, then add one MCP server or call the REST API with the same key.

### Connect EmailOctopus to your agent.

1. **Create an account** Sign up and add EmailOctopus in the console. Your API key is there too.

2. **Sign in to EmailOctopus in your Cloud Browser** Open your Cloud Browser in the console: your own Chrome in the cloud. Sign in to EmailOctopus there yourself, the way you always do, then press Enable for agents, read only or read and write. We never save your password, and your agent keeps working even when your computer is off.

3. **Add Cotlet to your agent** Paste the snippet for your client. The same server and key serve every app you connect, so you do this once.

   Claude Code:

```
claude mcp add --transport http cotlet \
  https://cotlet.dev/mcp/v1 \
  --header "Authorization: Bearer $COTLET_API_KEY"
```

   Cursor:

```
{
  "mcpServers": {
    "cotlet": {
      "url": "https://cotlet.dev/mcp/v1",
      "headers": {
        "Authorization": "Bearer ${COTLET_API_KEY}"
      }
    }
  }
}
```

   Codex:

```
# ~/.codex/config.toml
[mcp_servers.cotlet]
url = "https://cotlet.dev/mcp/v1"
bearer_token_env_var = "COTLET_API_KEY"
```

4. **Ask your agent** Ask in plain words. Your agent finds the EmailOctopus tools on the server and calls them for you; anything that reaches other people waits for your OK unless you switch that off for a tool.

```
In my EmailOctopus list Newsletter, check how the "Autumn offer" campaign did. Make a segment of everyone who was sent it and did not open it, duplicate the campaign with the subject "Last chance: Autumn offer", send it to that segment and schedule it for Thursday 9:00 London time.
```

### Call EmailOctopus from your scripts.

1. **Export your API key** Your scripts use the same API key as your agent. Keep it in an environment variable, never in your code.

```
export COTLET_API_KEY="cotlet_..."
```

2. **Call a tool** Every tool is an endpoint under /api/v1/emailoctopus with its own method and path, listed with the endpoints above. Path parameters go in the URL; the other parameters go in the query for GET and DELETE and in a JSON body otherwise.

```
curl -X POST https://cotlet.dev/api/v1/emailoctopus/campaigns/d5e8a3b1-62c9-4e70-8a14-9f0b7c2d6e83/schedule \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"date":"2026-10-22","time":"09:00","timezone":"Europe/London"}'
```

3. **Read the result** You get plain JSON back, ready for your script. A failed call costs nothing.

```
{
  "campaign_id": "d5e8a3b1-62c9-4e70-8a14-9f0b7c2d6e83",
  "name": "Autumn offer, last chance",
  "status": "scheduled",
  "scheduled_for": "2026-10-22T09:00:00+01:00",
  "timezone": "Europe/London"
}
```

## Why use Cotlet for EmailOctopus?

**Built for agents**

- One MCP server for every app you connect.
- The same tools as a REST API for scripts and cron jobs.
- Works with Claude Code, Codex and Cursor.

**Your login stays yours**

- You sign in to EmailOctopus yourself, in your own Cloud Browser. We never save your password; the profile is encrypted with AES-256-GCM, the cipher 1Password uses.
- A+ on Qualys SSL Labs, securityheaders.com and Mozilla Observatory.
- The model never sees a login.
- No stored passwords, no CAPTCHA solving, no MFA bypass.

**You stay in control**

- Scope each API key: its apps, its tools, read only or read and write.
- Anything that reaches other people waits for your OK, so a leaked key cannot post or message as you.
- Every background request listed in your Background activity. Disable for agents in one click.

**Kept working for you**

- We test every integration every 6 hours.
- When EmailOctopus changes, the tool pauses until we fix it.
- Failed calls cost nothing.

## Is it safe to connect EmailOctopus to Cotlet?

Yes. You sign in to EmailOctopus yourself, in your own Cloud Browser, and we never save your password. Your agents only get EmailOctopus once you enable it, and every background request is listed. The browser profile is stored encrypted with AES-256-GCM, the same cipher 1Password uses for its vaults and Apple for iCloud Keychain. Independent public scanners grade cotlet.dev A+ and find it clean; click a result to rerun it yourself.

- **A+ on Qualys SSL Labs**: Encryption in transit: TLS setup and certificates, on all four server addresses. [Live result](https://www.ssllabs.com/ssltest/analyze.html?d=cotlet.dev)
- **A+ on securityheaders.com**: Browser protections sent with every page, all six headers present. [Live result](https://securityheaders.com/?q=cotlet.dev&followRedirects=on)
- **A+ on Mozilla Observatory**: Mozilla's web security baseline: score 120 of 100, 12 of 12 tests passed. [Live result](https://developer.mozilla.org/en-US/observatory/analyze?host=cotlet.dev)
- **Clean on Sucuri SiteCheck**: No malware, spam or defacement, and not on any of 9 blocklists, Google Safe Browsing included. [Live result](https://sitecheck.sucuri.net/results/cotlet.dev)

[How Cotlet protects your access](https://cotlet.dev/security.md)

### Common concerns

**Who runs Cotlet?**

Cotlet is run by Take Group, a Polish software company working since 2019. Take Group runs about 3,200 websites on its own systems and has its own DevOps team for infrastructure security. We built and used integrations like this inside the company for years before opening them as Cotlet.

**Is this an official EmailOctopus integration?**

No, Cotlet is independent of EmailOctopus. EmailOctopus's own API is too limited for this work. Cotlet works through your own EmailOctopus account, the way you use EmailOctopus in the browser, so you need no partner approval and no developer setup.

**What about client data and GDPR?**

Cotlet is run from the EU and follows the GDPR. Cloud Browsers run in Finland, a Tier 1 country in the ITU Global Cybersecurity Index 2024. Data passes through a call and is not kept after it.

**Can I start with read only?**

Yes. Enable the app for agents as read only, or make the API key read only, and anything that reaches other people waits for your OK unless you switch that off per tool.

**Is it reliable?**

Every Cotlet service is checked every 3 minutes from Europe, North America, Asia and Australia. The live results and any outage are public at status.cotlet.dev.

**How do I stop?**

Press Disable for agents next to EmailOctopus in your console: your agents lose access at once and you stay signed in. Signing out of EmailOctopus in the browser works too, and Reset browser deletes the whole profile.

## Is there a EmailOctopus MCP server on GitHub?

Yes. Community EmailOctopus MCP servers exist on GitHub, usually maintained by one person. They run on the public API with your API key, so they read lists, contacts and reports but cannot create or send a campaign. You install and fix them yourself. Cotlet hosts the same kind of server for you, adds the campaign and segment work the API leaves out, and our team keeps it working.

|  | GitHub MCP server | Cotlet |
|---|---|---|
| Setup | Clone the repo, install it, add your API key to each MCP client | Sign up, sign in to EmailOctopus once, add one MCP server or API key |
| When EmailOctopus changes | It breaks until you or the maintainer fix it | Our team tests it daily and fixes it for you; failed calls are free |
| Your EmailOctopus session | An API key in a file on your computer, readable by any program you run | In your own Cloud Browser in the EU, profile encrypted, only for the apps you enable, disabled for agents in one click |
| When the session expires | The key works until you delete it; nothing covers the Dashboard-only jobs | Your Cloud Browser keeps you signed in; if EmailOctopus logs you out, your agent gets a link to sign in again |
| Upkeep | You update, monitor and debug it yourself | Nothing to host or update |
| Where it runs | Your computer, while it is on | Hosted: Claude Code, Codex, Cursor, n8n and scripts, also on a schedule |
| Price | Free, paid for with your time | Free 7-day trial, then pay-as-you-go credit packs, no subscription |

### Which one fits you

**Pick Cotlet if**

- you are not a developer, or you do not want to maintain a server
- you need it to keep working when EmailOctopus changes, without checking it yourself
- your agent or a script should run it on a schedule, also while your computer is off

**Pick an open-source server if**

- you are comfortable installing, updating and fixing it yourself
- you want your sign-in to stay on your own computer
- you only need it now and then, from one MCP client

## How much does the EmailOctopus API cost?

Free 7-day trial with 2,000 credits, no card needed. After that, the EmailOctopus API is pay as you go with no limit on apps: Credit packs from $29 for 5,000 credits, one-time, no subscription. A successful call uses 20 to 30 credits (25 for most tools, about $0.10 to $0.15), your Cloud Browser uses 50 credits a day while it has an app enabled for agents, however many apps that is, and an agent driving the browser itself uses 5 credits a minute. Credit packs stay valid for 12 months and stack, so unused credits carry over.

| Credits | Price, one time | Calls at 25 credits | Per 1,000 credits |
|---|---|---|---|
| 5,000 | $29 | 200 | $5.80 |
| 15,000 | $79 | 600 | $5.27 |
| 32,000 | $149 | 1,280 | $4.66 |
| 60,000 | $249 | 2,400 | $4.15 |

Only successful calls use credits; failed calls and timeouts cost nothing. At a balance of 0 calls pause, never a surprise charge. Authenticate with the `Authorization: Bearer` header. [See full pricing](https://cotlet.dev/pricing.md)

## How Cotlet holds your access

Cotlet hosts MCP servers and REST APIs for apps with no usable API. Your agent works in your own EmailOctopus account.

- **Company details:** Cotlet is run by Take Group sp. z o.o., a company registered in Poland. Its full address and registration numbers are in the Terms of service. [Terms of service](https://cotlet.dev/terms)
- **Your sign-in:** You sign in to EmailOctopus yourself, in your own Cloud Browser: a Chrome we run for you in the EU, one per app. We never save your password (password saving is off), the profile is stored encrypted with AES-256-GCM, and your agents get EmailOctopus only after you enable it. When EmailOctopus signs you out, your agent gives you a link to sign in again. [Security](https://cotlet.dev/security.md)
- **Revoking access:** Press Disable for agents next to EmailOctopus, sign out of EmailOctopus in your Cloud Browser, or reset the browser. Every background request is listed in your Background activity. Actions that reach other people wait for your OK unless you switch that off per tool.
- **What we never do:** Store passwords, solve CAPTCHAs or bypass MFA.
- **EmailOctopus's terms:** You use your own EmailOctopus account and stay responsible for following EmailOctopus's terms. Cotlet is independent and not affiliated with EmailOctopus. [Terms](https://cotlet.dev/terms)
- **Contact:** Questions about the company, security or an app: [contact@cotlet.dev](mailto:contact@cotlet.dev)

## Frequently asked questions

**How do I get access?**

Sign up free, open EmailOctopus in the console and press Request access. Then you create your API key and connect EmailOctopus there.

**Do I need to be technical?**

No. You sign in to EmailOctopus once in your Cloud Browser, a normal Chrome you open from the console, and paste one command into your agent, or one URL into n8n. Your agent can walk you through it. There is no server to install, update or fix.

**Is it safe to connect EmailOctopus to Cotlet?**

Yes. You sign in to EmailOctopus yourself, in your own Cloud Browser in the EU, and we never save your password. Your agents only get EmailOctopus once you enable it, every background request is listed, and the browser profile is stored encrypted with AES-256-GCM, the cipher 1Password uses for its vaults. The AI model never sees a login, posts and messages wait for your OK, and Disable for agents cuts access in one click. Independent scanners grade cotlet.dev A+ on Qualys SSL Labs, securityheaders.com and Mozilla Observatory; live results are on https://cotlet.dev/security.

**Is a hosted server safer than a local one? My EmailOctopus sign-in would leave my computer.**

On Cotlet you sign in inside your own Cloud Browser, which only you open, and its profile is stored encrypted with AES-256-GCM in the EU. Agents get only the apps you enable, and every background request is listed. A local server keeps your EmailOctopus cookie in a plain file on your computer, readable by any program you run, and stops when your computer is off.

**Why does Cotlet send requests instead of clicking in my browser?**

To be fast, Cotlet doesn't click through EmailOctopus's pages. It sends the same requests your browser would, from your browser's IP with its cookies, without opening a window. EmailOctopus sees the same browser and IP you signed in with, and every request is listed in your Background activity.

**What if someone gets my Cotlet API key?**

The key holds no EmailOctopus login or cookies, it only asks Cotlet to run a tool. It can call only the apps and tools you gave it, and a read-only key changes nothing. Anything that reaches other people, like posts, comments or messages, waits for your OK in the dashboard by default, so a leaked key cannot post or message as you. When you switch approval off for a scheduled job, give that job its own key limited to that one tool. Every call is in your activity log, and deleting the key ends access at once.

**Why a signed-in browser and not OAuth, like other integration platforms?**

EmailOctopus offers no OAuth token you can simply grant for these tools: its official API leaves them out or needs a developer app, a plan or an approval first (see the official API section above). That is why Cotlet sets the limits itself: per key, per tool, with your approval before anything reaches other people. Cotlet is run by Take Group sp. z o.o., an EU company (VAT PL6342984273).

**Which EmailOctopus plan or access level does my agent need?**

Cotlet works in the account you sign in with, so your plan and access level still apply. Extra users with their own access level (Admin, Manager, Analyst, Accountant) are a Pro feature, and an Analyst can only view reports. On the free Starter plan reports stay for 30 days and a list can have 10 tags, against 50 on Pro (EmailOctopus Help: Invite users to your account, Using tags, pricing page).

**Can my agent write or design the email?**

No. The tools set the name, subject, preview text, sender, recipients and sending time of a campaign, and duplicate_campaign copies a campaign you already designed. The design itself stays in the drag and drop editor or your own HTML, because EmailOctopus has no API for creating emails and says they are created in the Dashboard (EmailOctopus Help: API limits).

**Can my agent post or send messages in EmailOctopus without asking me?**

No. Every call to schedule_campaign, send_campaign or unsubscribe_contacts waits for your OK by default. For scheduled automations you can switch confirmation off per tool in your dashboard, for example only for approvals. create_segment, duplicate_campaign, update_campaign, set_campaign_recipients, unschedule_campaign runs without asking, because it sends nothing to anyone and one call undoes it.

**Can I use the EmailOctopus API in n8n?**

Yes. Add https://cotlet.dev/mcp/v1 with your API key in n8n's MCP Client node, or call its endpoints under https://cotlet.dev/api/v1/emailoctopus from the HTTP Request node.

---

Give your AI agents your signed-in browser.

**Product:** [Integrations](https://cotlet.dev/integrations.md) · [Use cases](https://cotlet.dev/use-cases.md) · [How it works](https://cotlet.dev/how-it-works.md) · [Pricing](https://cotlet.dev/pricing.md) · [Security](https://cotlet.dev/security.md)

**Resources:** [Blog](https://cotlet.dev/blog.md) · [API docs](https://cotlet.dev/docs.md) · [Help center](https://cotlet.dev/help.md) · [Changelog](https://cotlet.dev/changelog.md) · [GitHub](https://github.com/cotletdev/cotlet)

**Solutions:** [For developers](https://cotlet.dev/for-developers.md) · [For automation agencies](https://cotlet.dev/for-agencies.md)

**Company:** [About](https://cotlet.dev/about.md) · [AI info: company facts](https://cotlet.dev/ai-info.md) · [Contact](https://cotlet.dev/contact.md)

**Legal:** [Terms of service](https://cotlet.dev/terms) · [Privacy policy](https://cotlet.dev/privacy) · [Refund policy](https://cotlet.dev/refunds) · [Acceptable use](https://cotlet.dev/acceptable-use) · [Cookie policy](https://cotlet.dev/cookies) · [DPA](https://cotlet.dev/dpa) · [Subprocessors](https://cotlet.dev/subprocessors)

**Elsewhere:** [Status page](https://status.cotlet.dev) · [Cotlet on GitHub](https://github.com/cotletdev) · [Cotlet on X](https://x.com/cotletdev) · [Cotlet on LinkedIn](https://www.linkedin.com/company/cotletdev) · [Cotlet on Product Hunt](https://www.producthunt.com/products/cotlet) · [Cotlet on Crunchbase](https://www.crunchbase.com/organization/cotlet) · [Cotlet on SaaSHub](https://www.saashub.com/cotlet)

Cotlet is an independent service. It is not affiliated with, endorsed by or sponsored by any of the products listed on this site. Product names are trademarks of their respective owners.

## For AI agents: sign your user up

Is your user asking you to sign them up for Cotlet? You can do it for them, no account or key needed.

1. Read the fields and their allowed values: GET https://cotlet.dev/api/v1/access-requests
2. Ask the user for each value: email, apps, what you will do with them. If they leave the password to you, generate a strong one and show it to them.
3. Show the user what you will send, then POST it as JSON to https://cotlet.dev/api/v1/access-requests.

One call creates the account and sends the access request; we email the user when access is granted.
