> ## Documentation Index
> Fetch the complete documentation index at: https://docs.consile.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# API reference: HubSpot Marketing Email

> All 19 tools in the HubSpot Marketing Email connector: 8 read tools covering emails, drafts, revisions, A/B variations and aggregated send statistics; 11 write tools for creating and managing marketing emails. WritePreview dry-run semantics and confirm:true contract documented.

HubSpot Marketing Email is a **read + guardrailed write** connector, called via
`tools/call` over `POST /hubspot-email/mcp`. The connector is connected through
OAuth (HubSpot login; see [Forbind HubSpot Marketing Email](/connect/forbind-hubspot-email)).

<Info>
  Endpoint: `https://mcp.consile.ai/hubspot-email/mcp`. HubSpot Marketing Email
  is its own named connector with only its own tools.
</Info>

<Warning>
  **Tier requirement.** The OAuth scopes `content` and `marketing-email` require the
  connected HubSpot portal to be on **Marketing Hub Professional or Enterprise**.
  Sending and publishing emails additionally needs **Enterprise** or the
  **transactional-email add-on**. A Starter or Free portal cannot grant the required
  scopes and will fail at the HubSpot consent screen.
</Warning>

***

## Write safety: guardrail model

The connector divides its write tools into two groups based on reversibility and
audience impact.

**Runs freely (no confirmation needed):**

* `create_email`: creates an unpublished draft; never sends.
* `update_email_draft`: edits the draft buffer only; the live/published version is
  unchanged.
* `clone_email`: produces a new draft; no audience impact.
* `create_email_ab_variation`: creates a draft variant; does not send.

**Requires `confirm: true`:**

* `update_email`: edits the live/current record (can change the audience or content
  of an already-published or scheduled email).
* `publish_email`: sends the email to real recipients. Highest-risk action.
* `unpublish_email`: cancels a scheduled send or unpublishes a published email.
* `delete_email`: soft-archives the email.
* `reset_email_draft`: discards unsaved draft changes (destructive; cannot be undone).
* `restore_email_revision_to_draft`: overwrites the draft buffer with a previous
  revision.
* `restore_email_revision`: replaces the live version with a previous revision.

Without `confirm: true`, every confirm-gated tool returns a `WritePreview` dry-run
and calls no HubSpot API. Sending is only reachable through the explicitly-confirmed
`publish_email` tool. `create_email` and `update_email_draft` can never publish or
schedule a send: the `state`/`publishDate`/`sendOnPublish` fields are intentionally
absent from those tools.

This is a designed-in safety default (connector-local application logic), not an
unbreakable platform gate. See
[Handlinger & guardrails](/essentials/handlinger-og-guardrails) for the full
cross-connector policy.

### WritePreview shape

When a write action requires confirmation but `confirm` is omitted or `false`, the
tool returns this shape instead of calling HubSpot:

```json theme={null}
{
  "preview": {
    "action": "publish_email",
    "summary": "PUBLISH/SEND marketing email 123456 to its configured recipients.",
    "request": {
      "method": "POST",
      "path": "/marketing/v3/emails/123456/publish",
      "body": {}
    },
    "confirmHint": "Re-run the same call with confirm: true to apply this change."
  }
}
```

To apply, re-run the identical call with `confirm: true` added.

***

## Shared parameters

### Paging

List tools return a HubSpot `{ total, results, paging }` envelope. To fetch the
next page, pass the cursor from `paging.next.after` as the `after` argument.

<ParamField path="limit" type="integer" default="20">
  Max items to return in this page (1-100).
</ParamField>

<ParamField path="after" type="string">
  Paging cursor from a previous response's `paging.next.after`.
</ParamField>

### Email id

All per-email tools accept `emailId`: the numeric HubSpot marketing email id.

### Timestamps

Time-range fields accept ISO 8601 strings, e.g. `2026-01-01T00:00:00Z`.

***

## Read tools (8 total)

### list\_emails

List marketing emails with paging and filtering. Pass `includeStats: true` to
include aggregated post-send statistics per email in the same response.

<ParamField path="limit" type="integer" default="20" />

<ParamField path="after" type="string" />

<ParamField path="sort" type="string">
  Field to sort by; prefix with `-` for descending, e.g. `-updatedAt`.
</ParamField>

<ParamField path="archived" type="boolean">
  List archived emails instead of live ones.
</ParamField>

<ParamField path="campaign" type="string">
  Filter by campaign GUID.
</ParamField>

<ParamField path="type" type="string">
  Filter by email type: `BATCH_EMAIL`, `AB_EMAIL`, `AUTOMATED_EMAIL`, `RSS_EMAIL`.
</ParamField>

<ParamField path="isPublished" type="boolean">
  Filter by published state.
</ParamField>

<ParamField path="includeStats" type="boolean">
  Include post-send statistics in each result.
</ParamField>

<ParamField path="createdAfter" type="string">ISO 8601 lower bound on creation time.</ParamField>
<ParamField path="createdBefore" type="string">ISO 8601 upper bound on creation time.</ParamField>
<ParamField path="updatedAfter" type="string">ISO 8601 lower bound on update time.</ParamField>
<ParamField path="updatedBefore" type="string">ISO 8601 upper bound on update time.</ParamField>
<ParamField path="publishedAfter" type="string">ISO 8601 lower bound on publish time.</ParamField>
<ParamField path="publishedBefore" type="string">ISO 8601 upper bound on publish time.</ParamField>

**Returns:** `{ total, results[], paging }`: each result includes the email id,
name, subject, type, published state, campaign, language, and (when requested)
aggregated send stats.

***

### get\_email

Get the full details of one marketing email by id (the live/current version).

<ParamField path="emailId" type="string" required />

<ParamField path="includeStats" type="boolean">
  Include aggregated post-send statistics in the response.
</ParamField>

<ParamField path="variantStats" type="boolean">
  Include per-variant stats for A/B emails.
</ParamField>

<ParamField path="archived" type="boolean">
  Look up an archived email.
</ParamField>

**Returns:** Full email object: id, name, subject, type, state, publishDate, from,
to, content, campaign, language, and (when requested) stats.

***

### get\_email\_draft

Read the current unpublished draft (working copy) of a marketing email to inspect
pending edits before publishing.

<ParamField path="emailId" type="string" required />

**Returns:** The draft object for the email, including any unsaved edits not yet
visible on the live version.

***

### list\_email\_revisions

List the historical revisions (version snapshots) of a marketing email, with paging.

<ParamField path="emailId" type="string" required />

<ParamField path="limit" type="integer" default="20" />

<ParamField path="before" type="string">
  Paging cursor: revisions before this token.
</ParamField>

<ParamField path="after" type="string" />

**Returns:** `{ results[], paging }`: each revision includes revision id,
created time, and a snapshot of the email at that point.

***

### get\_email\_revision

Get a single historical revision by revision id.

<ParamField path="emailId" type="string" required />

<ParamField path="revisionId" type="string" required>
  The revision/version id (from `list_email_revisions`).
</ParamField>

**Returns:** The full revision snapshot.

***

### get\_email\_ab\_variation

Get the opposite A/B variation of an A/B marketing email: given variation A it
returns B, and vice versa.

<ParamField path="emailId" type="string" required />

**Returns:** The counterpart variation object.

***

### get\_email\_statistics

Get aggregated post-send statistics across emails sent in a time span: sent,
delivered, open, click, bounce counters and ratios, plus the list of email ids
sent. Matches the in-app Email Performance view.

<ParamField path="startTimestamp" type="string">
  Start of the time span (ISO 8601).
</ParamField>

<ParamField path="endTimestamp" type="string">
  End of the time span (ISO 8601).
</ParamField>

<ParamField path="emailIds" type="string[]">
  Restrict to these email ids. Omit to include all sent emails in the span.
</ParamField>

<ParamField path="property" type="string">
  Restrict the returned statistic properties to one named field.
</ParamField>

**Returns:** Aggregated counters and ratios: sent, delivered, open rate, click
rate, bounce rate, unsubscribe rate, and the email ids included.

***

### get\_email\_statistics\_histogram

Get time-bucketed statistics over a span at a chosen interval. Each bucket carries
the aggregated stats of emails sent in that interval. Useful for charting
performance trends.

<ParamField path="interval" type="string">
  Bucket size. One of: `HOUR`, `DAY`, `WEEK`, `MONTH`, `QUARTER`, `YEAR`,
  `MINUTE`, `QUARTER_HOUR`, `SECOND`.
</ParamField>

<ParamField path="startTimestamp" type="string">
  Start of the time span (ISO 8601).
</ParamField>

<ParamField path="endTimestamp" type="string">
  End of the time span (ISO 8601).
</ParamField>

<ParamField path="emailIds" type="string[]">
  Restrict to these email ids.
</ParamField>

**Returns:** An array of time-bucketed stat objects, each with a timestamp and the
same counters as `get_email_statistics`.

***

## Write tools (11 total)

<Warning>
  Write tools call the HubSpot Marketing Emails API. Drafts and safe edits run
  freely. Actions that publish to the live site, send to recipients, cancel, delete,
  or overwrite draft work require `confirm: true`. Without it the tool returns a
  [WritePreview](#writepreview-shape) and calls no API. See
  [Handlinger & guardrails](/essentials/handlinger-og-guardrails).
</Warning>

### Shared writable fields

The `create_email`, `update_email`, and `update_email_draft` tools share a common
set of content and sender fields:

<ParamField path="subject" type="string">Email subject line.</ParamField>

<ParamField path="language" type="string">
  Locale code, e.g. `en`, `en-us`, `da-dk`.
</ParamField>

<ParamField path="campaign" type="string">
  Marketing campaign GUID to associate the email with.
</ParamField>

<ParamField path="businessUnitId" type="integer">
  Business Unit id (requires the Business Units / Brands add-on).
</ParamField>

<ParamField path="folderIdV2" type="integer">
  Destination folder id.
</ParamField>

<ParamField path="fromName" type="string">
  Sender display name.
</ParamField>

<ParamField path="replyTo" type="string">
  Reply-to email address.
</ParamField>

<ParamField path="customReplyTo" type="string">
  Custom reply-to email address.
</ParamField>

<ParamField path="contactListIds" type="string[]">
  Contact list ids to send to (assembled into `to.contactLists.include`).
</ParamField>

<ParamField path="templatePath" type="string">
  Path to the template or theme file the email uses.
</ParamField>

<ParamField path="plainTextVersion" type="string">
  Plain-text version of the email body.
</ParamField>

***

### create\_email

Create a new marketing email as an unpublished draft. The state is forced to `DRAFT`
on creation: this tool can never publish or schedule a send. Only `name` is required.
Publish later with `publish_email`.

**Runs freely. No confirmation needed.**

<ParamField path="name" type="string" required>
  Internal name of the email.
</ParamField>

<ParamField path="subject" type="string" />

<ParamField path="language" type="string" />

<ParamField path="campaign" type="string" />

<ParamField path="businessUnitId" type="integer" />

<ParamField path="folderIdV2" type="integer" />

<ParamField path="fromName" type="string" />

<ParamField path="replyTo" type="string" />

<ParamField path="customReplyTo" type="string" />

<ParamField path="contactListIds" type="string[]" />

<ParamField path="templatePath" type="string" />

<ParamField path="plainTextVersion" type="string" />

**Returns:** The newly created email object with `state: "DRAFT"`.

***

### update\_email

Sparse-update a marketing email's fields on the **live/current version**, not just
the draft buffer. Does not publish or send, but it can change the audience or content
of an already-published or scheduled email.

**Requires `confirm: true`.**

<ParamField path="emailId" type="string" required />

<ParamField path="name" type="string" />

<ParamField path="subject" type="string" />

<ParamField path="language" type="string" />

<ParamField path="campaign" type="string" />

<ParamField path="businessUnitId" type="integer" />

<ParamField path="folderIdV2" type="integer" />

<ParamField path="fromName" type="string" />

<ParamField path="replyTo" type="string" />

<ParamField path="customReplyTo" type="string" />

<ParamField path="contactListIds" type="string[]" />

<ParamField path="templatePath" type="string" />

<ParamField path="plainTextVersion" type="string" />

<ParamField path="confirm" type="boolean">
  Set `true` to apply. Omit or `false` to receive a WritePreview.
</ParamField>

**Returns:** The updated email object, or a WritePreview if `confirm` is not `true`.

***

### update\_email\_draft

Create or update only the draft (working copy) of a marketing email without touching
the live/published version. Does not publish or send.

**Runs freely. No confirmation needed.**

<ParamField path="emailId" type="string" required />

<ParamField path="name" type="string" />

<ParamField path="subject" type="string" />

<ParamField path="language" type="string" />

<ParamField path="campaign" type="string" />

<ParamField path="businessUnitId" type="integer" />

<ParamField path="folderIdV2" type="integer" />

<ParamField path="fromName" type="string" />

<ParamField path="replyTo" type="string" />

<ParamField path="customReplyTo" type="string" />

<ParamField path="contactListIds" type="string[]" />

<ParamField path="templatePath" type="string" />

<ParamField path="plainTextVersion" type="string" />

**Returns:** The updated draft object.

***

### clone\_email

Clone an existing marketing email into a new draft, optionally renaming it and
setting a locale.

**Runs freely. No confirmation needed.**

<ParamField path="id" type="string" required>
  The id of the marketing email to clone.
</ParamField>

<ParamField path="cloneName" type="string">
  Name for the new cloned email.
</ParamField>

<ParamField path="language" type="string">
  Locale for the clone, e.g. `da-dk`.
</ParamField>

**Returns:** The newly created draft clone.

***

### create\_email\_ab\_variation

Create an A/B test variation of a marketing email. The variation is created as a
draft variant and does not send.

**Runs freely. No confirmation needed.**

<ParamField path="contentId" type="string" required>
  The id of the email to create an A/B variation of.
</ParamField>

<ParamField path="variationName" type="string" required>
  Name of the new variation.
</ParamField>

**Returns:** The newly created draft A/B variation object.

***

### reset\_email\_draft

Discard unsaved draft changes, resetting the draft back to the latest published
version. This cannot be undone.

**Requires `confirm: true`.**

<ParamField path="emailId" type="string" required />

<ParamField path="confirm" type="boolean">
  Set `true` to apply. Omit or `false` to receive a WritePreview.
</ParamField>

***

### restore\_email\_revision\_to\_draft

Copy a previous revision's content into the current draft without publishing.
Overwrites the draft buffer.

**Requires `confirm: true`.**

<ParamField path="emailId" type="string" required />

<ParamField path="revisionId" type="string" required>
  The revision id to restore into the draft (from `list_email_revisions`).
</ParamField>

<ParamField path="confirm" type="boolean">
  Set `true` to apply. Omit or `false` to receive a WritePreview.
</ParamField>

***

### restore\_email\_revision

Restore a previous revision as the new current/live version of the marketing email.
Replaces the live version.

**Requires `confirm: true`.**

<ParamField path="emailId" type="string" required />

<ParamField path="revisionId" type="string" required>
  The revision id to restore (from `list_email_revisions`).
</ParamField>

<ParamField path="confirm" type="boolean">
  Set `true` to apply. Omit or `false` to receive a WritePreview.
</ParamField>

***

### publish\_email

Publish or send the marketing email to its configured recipients. This is the
highest-risk action: it sends real email to the customer's contact lists. Requires
`confirm: true`. Needs the `marketing-email` (or `transactional-email`) scope on a
Marketing Hub Enterprise portal (or transactional-email add-on).

**Requires `confirm: true`.**

<ParamField path="emailId" type="string" required />

<ParamField path="confirm" type="boolean">
  Set `true` to apply. Omit or `false` to receive a WritePreview.
</ParamField>

***

### unpublish\_email

Unpublish a published email or cancel a scheduled send.

**Requires `confirm: true`.**

<ParamField path="emailId" type="string" required />

<ParamField path="confirm" type="boolean">
  Set `true` to apply. Omit or `false` to receive a WritePreview.
</ParamField>

***

### delete\_email

Delete a marketing email (soft-archive). The email can be retrieved from the
archived state, but deletion is treated as irreversible here.

**Requires `confirm: true`.**

<ParamField path="emailId" type="string" required />

<ParamField path="confirm" type="boolean">
  Set `true` to apply. Omit or `false` to receive a WritePreview.
</ParamField>

***

## Code examples

<CodeGroup>
  ```json Request: list_emails (unpublished, most recently updated first) theme={null}
  {
    "name": "hubspot-email__list_emails",
    "arguments": {
      "isPublished": false,
      "sort": "-updatedAt",
      "limit": 20
    }
  }
  ```

  ```json Request: get_email_statistics (last 30 days) theme={null}
  {
    "name": "hubspot-email__get_email_statistics",
    "arguments": {
      "startTimestamp": "2026-05-01T00:00:00Z",
      "endTimestamp": "2026-05-31T23:59:59Z"
    }
  }
  ```

  ```json Request: update_email_draft (runs freely) theme={null}
  {
    "name": "hubspot-email__update_email_draft",
    "arguments": {
      "emailId": "123456",
      "subject": "New subject line",
      "fromName": "Consile Team"
    }
  }
  ```

  ```json Request: publish_email (dry-run, confirm omitted) theme={null}
  {
    "name": "hubspot-email__publish_email",
    "arguments": {
      "emailId": "123456"
    }
  }
  ```

  ```json Request: publish_email (apply with confirm) theme={null}
  {
    "name": "hubspot-email__publish_email",
    "arguments": {
      "emailId": "123456",
      "confirm": true
    }
  }
  ```

  ```json Request: clone_email (runs freely) theme={null}
  {
    "name": "hubspot-email__clone_email",
    "arguments": {
      "id": "123456",
      "cloneName": "Summer Newsletter (DK)",
      "language": "da-dk"
    }
  }
  ```
</CodeGroup>

<Note>
  Tool names are namespaced `hubspot-email__<tool>` in Claude/ChatGPT (the AI invokes
  these automatically). The bare names, e.g. `publish_email`, are used in this
  reference for readability.
</Note>

<Note>
  An expired or revoked access token surfaces as `AccessTokenExpiredError`. HubSpot
  access tokens are short-lived (\~30 minutes) and renewed automatically in the
  background via the stored refresh token. If automatic renewal fails, reconnect via
  the portal. See [Errors & limits](/developers/errors-and-limits).
</Note>

***

## Revocation

There is no upstream revoke in the portal in v1. To revoke access, uninstall the
Consile app in your HubSpot portal settings. Disconnecting in the Consile portal
deletes the stored token immediately, but the HubSpot app authorization remains
until you uninstall it from HubSpot.
