Base URL: /api/email-campaigns
The Email Campaign API enables creating, managing, and sending personalized email campaigns using Microsoft Graph integration. Campaigns combine data files, email templates, and Word document attachments for sophisticated email automation.
All endpoints require JWT authentication:
Authorization: Bearer
---
Create a new email campaign configuration.
Request:
{
"campaignName": "Q1 Welcome Campaign",
"campaignMode": "broadcast",
"dataFileId": "uuid-of-data-file",
"dataFileName": "customers.csv",
"recipientListId": null,
"emailBodyTemplateId": "uuid-of-html-template",
"emailBodyTemplateName": "Welcome Template",
"attachmentTemplateId": "uuid-of-word-template",
"attachmentTemplateName": "Welcome Packet.docx",
"emailField": "Email",
"subjectField": "SubjectLine",
"defaultSubject": "Welcome to Data Publisher!",
"dataFlow": "single",
"ccField": null,
"bccField": null,
"replyToField": null,
"fromNameField": null,
"graphicLibraryId": "uuid-of-image-library",
"generateAttachments": true,
"attachmentFormat": "pdf",
"trackOpens": true,
"trackClicks": true,
"trackReplies": false,
"testMode": false,
"recordCount": 150,
"staticAttachments": [],
"wizardProgress": 100
}
Required Fields:
campaignName: Display name for campaign
dataFileId: ID of data file containing recipients
dataFileName: Name of data file
emailField: Column name for recipient email
defaultSubject: Email subject (or field name if using subjectField)
emailBodyTemplateId: HTML template ID
emailBodyTemplateName: Template name
Optional Fields:
attachmentTemplateId: Word template for personalized attachments
attachmentFormat: "docx" or "pdf" (default: "pdf")
subjectField: Column name for dynamic subject lines
ccField, bccField: Column names for CC/BCC recipients
replyToField: Column name for reply-to address
fromNameField: Column name for sender name
graphicLibraryId: Image library for HTML template
trackOpens, trackClicks: Enable tracking (default: true)
testMode: Send to limited recipients for testing
staticAttachments: Array of additional files
Success Response (201):
{
"success": true,
"campaign": {
"Id": "uuid-of-campaign",
"UserId": "user-uuid",
"CampaignName": "Q1 Welcome Campaign",
"Status": "draft",
"RecordCount": 150,
"CreatedAt": "2026-02-12T10:30:00Z"
},
"message": "Email campaign created successfully"
}
Validation Errors (400):
{
"success": false,
"error": "Missing required fields: campaignName, emailField"
}
{
"success": false,
"error": "Invalid attachment format. Must be 'docx' or 'pdf'"
}
---
Get all email campaigns for the authenticated user.
Query Parameters:
status (optional): Filter by status - "draft", "ready", "sending", "completed", "failed"
limit (optional): Number of results (default: 50)
offset (optional): Pagination offset (default: 0)
Example:
GET /api/email-campaigns?status=draft&limit=20
Success Response (200):
{
"success": true,
"campaigns": [
{
"Id": "uuid-1",
"CampaignName": "Q1 Welcome Campaign",
"Status": "draft",
"RecordCount": 150,
"CreatedAt": "2026-02-12T10:30:00Z",
"UpdatedAt": "2026-02-12T10:30:00Z"
},
{
"Id": "uuid-2",
"CampaignName": "Product Announcement",
"Status": "completed",
"RecordCount": 500,
"SentCount": 498,
"FailedCount": 2,
"CreatedAt": "2026-02-10T09:00:00Z",
"CompletedAt": "2026-02-10T11:45:00Z"
}
],
"total": 2,
"limit": 50,
"offset": 0
}
---
Get detailed information about a specific campaign.
URL Parameters:
id (uuid): Campaign ID
Success Response (200):
{
"success": true,
"campaign": {
"Id": "uuid-1",
"UserId": "user-uuid",
"CampaignName": "Q1 Welcome Campaign",
"CampaignMode": "broadcast",
"Status": "draft",
"DataFileId": "data-uuid",
"DataFileName": "customers.csv",
"EmailBodyTemplateId": "template-uuid",
"EmailBodyTemplateName": "Welcome Template",
"AttachmentTemplateId": "word-template-uuid",
"AttachmentTemplateName": "Welcome Packet.docx",
"EmailField": "Email",
"SubjectField": "SubjectLine",
"DefaultSubject": "Welcome to Data Publisher!",
"DataFlow": "single",
"GenerateAttachments": true,
"AttachmentFormat": "pdf",
"TrackOpens": true,
"TrackClicks": true,
"RecordCount": 150,
"SentCount": 0,
"FailedCount": 0,
"CreatedAt": "2026-02-12T10:30:00Z",
"UpdatedAt": "2026-02-12T10:30:00Z"
}
}
Error Response (404):
{
"success": false,
"error": "Campaign not found"
}
---
Update an existing campaign (must be in "draft" status).
URL Parameters:
id (uuid): Campaign ID
Request: Same structure as POST, all fields optional
{
"campaignName": "Q1 Welcome Campaign - Updated",
"trackOpens": false,
"testMode": true
}
Success Response (200):
{
"success": true,
"campaign": {
"Id": "uuid-1",
"CampaignName": "Q1 Welcome Campaign - Updated",
"UpdatedAt": "2026-02-12T11:00:00Z"
},
"message": "Campaign updated successfully"
}
Error Responses:
400 - Cannot Edit:
{
"success": false,
"error": "Cannot edit campaign in 'sending' or 'completed' status"
}
---
Delete a campaign (cannot delete campaigns that are currently sending).
URL Parameters:
id (uuid): Campaign ID
Success Response (200):
{
"success": true,
"message": "Campaign deleted successfully"
}
Error Response (400):
{
"success": false,
"error": "Cannot delete campaign while sending"
}
---
Send the email campaign.
URL Parameters:
id (uuid): Campaign ID
Request (optional):
{
"testMode": true,
"testRecipients": ["test@example.com"],
"limitRecords": 10
}
Success Response (200):
{
"success": true,
"jobId": "send-job-uuid",
"message": "Campaign sending started",
"estimatedDuration": "15 minutes",
"recipientCount": 150
}
Note: Sending is asynchronous. Use /api/email-campaigns/:id/status to check progress.
---
Check campaign sending status and progress.
URL Parameters:
id (uuid): Campaign ID
Success Response (200):
{
"success": true,
"status": {
"campaignStatus": "sending",
"progress": 45.5,
"sentCount": 68,
"failedCount": 2,
"remainingCount": 80,
"totalCount": 150,
"startedAt": "2026-02-12T10:45:00Z",
"estimatedCompletion": "2026-02-12T11:00:00Z",
"errors": [
{
"recipient": "invalid@email",
"error": "Invalid email address"
}
]
}
}
---
Pause a sending campaign.
Success Response (200):
{
"success": true,
"message": "Campaign paused",
"sentCount": 75,
"remainingCount": 75
}
---
Resume a paused campaign.
Success Response (200):
{
"success": true,
"message": "Campaign resumed",
"remainingCount": 75
}
---
Cancel a sending campaign.
Success Response (200):
{
"success": true,
"message": "Campaign cancelled",
"sentCount": 75,
"cancelledCount": 75
}
---
Send same email to all recipients with personalized fields.
{
"campaignMode": "broadcast",
"dataFlow": "single"
}
One email per record with all data.
---
{
"generateAttachments": true,
"attachmentFormat": "pdf",
"attachmentTemplateId": "word-template-uuid"
}
Process:
{
"attachmentFormat": "docx"
}
{
"staticAttachments": [
{
"fileName": "brochure.pdf",
"fileContent": "base64-encoded-content"
}
]
}
---
{
"trackOpens": true
}
Embeds invisible tracking pixel in emails.
{
"trackClicks": true
}
Rewrites links to track click-through.
Analytics Endpoint:
GET /api/email-campaigns/:id/analytics
Response:
{
"success": true,
"analytics": {
"sentCount": 150,
"openCount": 98,
"openRate": 65.3,
"clickCount": 45,
"clickRate": 30.0,
"bounceCount": 2,
"bounceRate": 1.3
}
}
---
Before sending to all recipients, test with a small group:
{
"testMode": true,
"testRecipients": ["test1@example.com", "test2@example.com"],
"limitRecords": 5
}
Benefits:
---
In email templates and subjects, use {{FieldName}} syntax:
Subject:
"Welcome {{FirstName}} to {{CompanyName}}!"
Email Body HTML:
Dear {{FirstName}} {{LastName}},
We're excited to have {{CompanyName}} as a customer!
Supported Fields:
---
/status endpoint during sending
---
---
const token = 'your-jwt-token';
// 1. Create campaign
const campaign = await fetch('http://localhost:3001/api/email-campaigns', {
method: 'POST',
headers: {
'Authorization': Bearer ${token},
'Content-Type': 'application/json'
},
body: JSON.stringify({
campaignName: 'Welcome Campaign',
dataFileId: 'data-uuid',
dataFileName: 'customers.csv',
emailBodyTemplateId: 'template-uuid',
emailBodyTemplateName: 'Welcome Email',
emailField: 'Email',
defaultSubject: 'Welcome {{FirstName}}!',
trackOpens: true,
trackClicks: true,
testMode: true
})
}).then(r => r.json());
// 2. Test send
await fetch(http://localhost:3001/api/email-campaigns/${campaign.campaign.Id}/send, {
method: 'POST',
headers: {
'Authorization': Bearer ${token},
'Content-Type': 'application/json'
},
body: JSON.stringify({
testMode: true,
testRecipients: ['test@example.com'],
limitRecords: 5
})
});
// 3. Check status
const status = await fetch(http://localhost:3001/api/email-campaigns/${campaign.campaign.Id}/status, {
headers: { 'Authorization': Bearer ${token} }
}).then(r => r.json());
console.log('Progress:', status.status.progress + '%');
// 4. Full send
await fetch(http://localhost:3001/api/email-campaigns/${campaign.campaign.Id}/send, {
method: 'POST',
headers: {
'Authorization': Bearer ${token},
'Content-Type': 'application/json'
},
body: JSON.stringify({
testMode: false
})
});
// 5. Get analytics later
const analytics = await fetch(http://localhost:3001/api/email-campaigns/${campaign.campaign.Id}/analytics, {
headers: { 'Authorization': Bearer ${token} }
}).then(r => r.json());
console.log('Open rate:', analytics.analytics.openRate + '%');
---