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

# Email Campaigns

> Send, schedule, AI-generate, and track email campaigns with the Gately SDK

The `GatelyCampaigns` class gives you full programmatic control over Gately's email campaign system — create and send campaigns, schedule them, generate content with AI, track stats, and manage attachments.

## Installation

```bash theme={null}
npm install @gately/sdk
```

## Setup

```typescript theme={null}
import { GatelyCampaigns } from '@gately/sdk'

const campaigns = new GatelyCampaigns({
  projectId: 'YOUR_PROJECT_ID',
  // apiUrl: 'https://api.usegately.com' // optional override
})
```

<Note>
  `GatelyCampaigns` works in both browser and Node.js environments. In Node.js it uses `GatelyNodeClient` internally; in the browser it uses `GatelyBrowserClient`.
</Note>

***

## Core Methods

### `list()`

Retrieve all campaigns for the project, newest first.

```typescript theme={null}
const list = await campaigns.list()
// Campaign[]
```

***

### `get(campaignId)`

Fetch a single campaign by ID.

```typescript theme={null}
const campaign = await campaigns.get('cmp_abc123')
console.log(campaign.status) // 'sent'
```

***

### `send(request)`

Create and send (or schedule) a campaign in one call.

```typescript theme={null}
const result = await campaigns.send({
  name: 'June Newsletter',
  subject: 'What we shipped this month',
  content: '<h1>June Update</h1><p>Here is what we built...</p>',

  // Pick one or more recipient sources:
  recipient_all_contacts: true,
  // recipient_emails: ['alice@example.com'],
  // recipient_list_ids: ['list_abc'],
  // recipient_segment_ids: ['seg_xyz'],
})

console.log(`Sent to ${result.successful_sends} of ${result.total_recipients}`)
```

**Scheduling** — pass `scheduled_at` to queue for later:

```typescript theme={null}
await campaigns.send({
  name: 'Product Launch',
  subject: 'Introducing our new feature!',
  content: '<p>Check it out.</p>',
  recipient_list_ids: ['list_abc123'],
  scheduled_at: '2025-07-01T09:00:00Z',
})
```

***

### `sendBulk(request)`

Send to a list of explicit recipient IDs (format: `customer_<email>`).

```typescript theme={null}
await campaigns.sendBulk({
  name: 'VIP Promo',
  subject: 'Exclusive offer for you',
  content: '<p>Here is your deal.</p>',
  recipient_ids: ['customer_alice@example.com', 'customer_bob@example.com'],
})
```

***

### `update(campaignId, updates)`

Update a `draft` or `scheduled` campaign. Cannot update campaigns that are `sending` or `sent`.

```typescript theme={null}
await campaigns.update('cmp_abc123', {
  name: 'June Newsletter (v2)',
  subject: 'Updated subject line',
  content: '<p>Revised content.</p>',
})
```

***

### `delete(campaignId)`

Delete a campaign. Cannot delete campaigns currently `sending`.

```typescript theme={null}
await campaigns.delete('cmp_abc123')
```

***

### `getStats(campaignId)`

Get delivery and engagement stats. The SDK automatically adds derived rate fields.

```typescript theme={null}
const stats = await campaigns.getStats('cmp_abc123')

console.log(`Delivery rate: ${stats.delivery_rate}%`)
console.log(`Open rate:     ${stats.open_rate}%`)
console.log(`Click rate:    ${stats.click_rate}%`)
```

| Field           | Description                |
| --------------- | -------------------------- |
| `sent`          | Total emails targeted      |
| `delivered`     | Accepted by mail servers   |
| `opened`        | Unique opens               |
| `clicked`       | Unique link clicks         |
| `bounced`       | Hard + soft bounces        |
| `complained`    | Spam complaints            |
| `delivery_rate` | `delivered / sent × 100`   |
| `open_rate`     | `opened / delivered × 100` |
| `click_rate`    | `clicked / opened × 100`   |

***

## AI Content Generation

### `aiGenerate(request)`

Generate a complete, inline-styled HTML email body using Gately's built-in AI.

```typescript theme={null}
const { html } = await campaigns.aiGenerate({
  campaignName: 'Summer Sale',
  subject: '50% off everything this weekend',
  tone: 'friendly', // 'professional' | 'friendly' | 'casual' | 'urgent'
})

// html is ready to pass directly to send()
await campaigns.send({
  name: 'Summer Sale',
  subject: '50% off everything this weekend',
  content: html,
  recipient_all_contacts: true,
})
```

***

### `aiSend(options)` — convenience helper

Generate content with AI and send in a single call.

```typescript theme={null}
const result = await campaigns.aiSend({
  campaignName: 'Product Update',
  subject: 'New features just dropped',
  tone: 'professional',
  recipient_all_contacts: true,
  // scheduled_at: '2025-07-01T09:00:00Z', // optional
})

console.log(`Sent to ${result.successful_sends} recipients`)
```

***

## Attachments

### `uploadAttachment(file)` — browser only

Upload a file and get back a base64 attachment object ready to pass into `send()`.

```typescript theme={null}
// Get file from an <input type="file"> element
const fileInput = document.querySelector<HTMLInputElement>('#attachment')
const file = fileInput!.files![0]

const { attachment } = await campaigns.uploadAttachment(file)

await campaigns.send({
  name: 'Monthly Report',
  subject: 'Your report is attached',
  content: '<p>Please find your report attached.</p>',
  recipient_emails: ['user@example.com'],
  attachments: [attachment],
})
```

**Allowed file types:** PDF, Word, Excel, plain text, CSV, JPEG, PNG, GIF, WebP\
**Max size:** 10 MB per file

***

## Diagnostics

### `testEmailConfig()`

Check your project's email sending configuration — useful for debugging domain setup.

```typescript theme={null}
const config = await campaigns.testEmailConfig()

console.log('Sending from:', config.fromEmail)
console.log('Domain status:', config.domainStatus)
console.log('Email binding:', config.emailBindingAvailable)
```

***

## Utility Helpers

### `waitForCompletion(campaignId)`

Poll a campaign until it reaches a terminal status (`sent`, `partially_sent`, or `failed`). Useful after scheduling.

```typescript theme={null}
const result = await campaigns.send({
  name: 'Launch',
  subject: 'We are live!',
  content: '<p>Check it out.</p>',
  recipient_all_contacts: true,
})

// Wait for it to finish sending
const final = await campaigns.waitForCompletion(result.campaign.id)
console.log('Final status:', final.status)
console.log('Delivered:', final.delivered_count)
```

Options:

```typescript theme={null}
await campaigns.waitForCompletion(
  campaignId,
  3000,    // poll every 3 seconds (default)
  120_000  // give up after 2 minutes (default)
)
```

***

## TypeScript Types

All types are exported from `@gately/sdk`:

```typescript theme={null}
import type {
  Campaign,
  CampaignStatus,
  SendCampaignRequest,
  SendBulkCampaignRequest,
  UpdateCampaignRequest,
  AIGenerateRequest,
  CampaignAttachment,
  SendCampaignResponse,
  CampaignStats,
  AIGenerateResponse,
  EmailConfigStatus,
  UploadAttachmentResponse,
} from '@gately/sdk'
```

### `CampaignStatus`

```typescript theme={null}
type CampaignStatus =
  | 'draft'
  | 'scheduled'
  | 'sending'
  | 'sent'
  | 'partially_sent'
  | 'failed'
```

### `SendCampaignRequest`

```typescript theme={null}
interface SendCampaignRequest {
  name: string
  subject: string
  content: string
  recipient_emails?: string[]
  recipient_list_ids?: string[]
  recipient_segment_ids?: string[]
  recipient_all_contacts?: boolean
  scheduled_at?: string          // ISO 8601
  attachments?: CampaignAttachment[]
}
```

### `CampaignStats`

```typescript theme={null}
interface CampaignStats {
  sent: number
  delivered: number
  opened: number
  clicked: number
  bounced: number
  complained: number
  // Added by SDK:
  delivery_rate?: number
  open_rate?: number
  click_rate?: number
}
```

***

## Complete Example

```typescript theme={null}
import { GatelyCampaigns } from '@gately/sdk'

const campaigns = new GatelyCampaigns({ projectId: 'YOUR_PROJECT_ID' })

async function runMonthlyNewsletter() {
  // 1. Generate content with AI
  const { html } = await campaigns.aiGenerate({
    campaignName: 'June Newsletter',
    subject: 'What we shipped in June',
    tone: 'friendly',
  })

  // 2. Send to all contacts
  const result = await campaigns.send({
    name: 'June Newsletter',
    subject: 'What we shipped in June',
    content: html,
    recipient_all_contacts: true,
  })

  console.log(`Campaign ID: ${result.campaign.id}`)
  console.log(`Sent: ${result.successful_sends} / ${result.total_recipients}`)

  // 3. Wait for completion and check stats
  const final = await campaigns.waitForCompletion(result.campaign.id)

  const stats = await campaigns.getStats(final.id)
  console.log(`Open rate:  ${stats.open_rate}%`)
  console.log(`Click rate: ${stats.click_rate}%`)
}

runMonthlyNewsletter()
```

***

## Related

<CardGroup cols={2}>
  <Card title="Send Campaign API" icon="paper-plane" href="/docs/api-reference/campaigns/send">
    REST endpoint reference
  </Card>

  <Card title="Campaign Stats API" icon="chart-bar" href="/docs/api-reference/campaigns/stats">
    Stats endpoint reference
  </Card>

  <Card title="AI Generate API" icon="wand-magic-sparkles" href="/docs/api-reference/campaigns/ai-generate">
    AI content generation endpoint
  </Card>

  <Card title="Features: Campaigns" icon="envelope" href="/docs/features/campaigns">
    Dashboard usage guide
  </Card>
</CardGroup>
