sendEmail()
Sends a transactional email via the Conviso.
Signature
async sendEmail(request: SendEmailRequest): Promise<Record<string, any>>
Parameters
request
- Type:
SendEmailRequestOptions - Required: Yes
- Description: Email configuration object
The request can be either template-based (using a transactional message ID) or raw (providing HTML directly).
Returns
Promise<Record<string, any>> - Response from the API containing the email delivery status.
Throws
- CDPEmailError: Custom error with details about the failure
- Validation errors: If required fields are missing or invalid
Email Types
Template-Based Email
Use a predefined email template from your Conviso:
await client.sendEmail({
to: '[email protected]',
identifiers: { id: 'user123' },
transactional_message_id: 'WELCOME_EMAIL',
message_data: {
name: 'John',
activation_link: 'https://example.com/activate/abc123'
}
});
Raw HTML Email
Send custom HTML without a template:
await client.sendEmail({
to: '[email protected]',
identifiers: { email: '[email protected]' },
from: '[email protected]',
subject: 'Welcome to Our Service',
body: '<h1>Welcome!</h1><p>Thanks for signing up.</p>',
});
Required Fields
For All Emails
to- Recipient email addressidentifiers- User identifier (must contain exactly one of:id,email, orcdp_id)
Additional Requirements for Raw Emails
When NOT using transactional_message_id, you must also provide:
from- Sender email addresssubject- Email subject linebody- HTML body content
Request Options
SendEmailRequestWithTemplate
Template-based email with optional overrides:
interface SendEmailRequestWithTemplate {
// Required
to: string;
identifiers: { id: string } | { email: string };
transactional_message_id: string | number;
// Optional
message_data?: Record<string, any>;
subject?: string; // Override template subject
body?: string; // Override template body
plaintext_body?: string; // Plain text version
reply_to?: string;
bcc?: string;
preheader?: string;
language?: string;
// Advanced options (see Unsupported Fields section)
headers?: Record<string, any>;
send_at?: number;
tracked?: boolean;
// ... more options
}
SendEmailRequestWithoutTemplate
Raw email without a template:
interface SendEmailRequestWithoutTemplate {
// Required
to: string;
identifiers: { id: string } | { email: string };
from: string;
subject: string;
body: string;
// Optional
plaintext_body?: string;
reply_to?: string;
bcc?: string;
preheader?: string;
message_data?: Record<string, any>;
// ... more options
}
Usage Examples
Welcome Email (Template)
await client.sendEmail({
to: '[email protected]',
identifiers: { id: 'user123' },
transactional_message_id: 'WELCOME_EMAIL',
message_data: {
name: 'John Doe',
activation_url: 'https://app.example.com/activate'
}
});
Password Reset (Template with Override)
await client.sendEmail({
to: '[email protected]',
identifiers: { id: 'user123' },
transactional_message_id: 'PASSWORD_RESET',
subject: 'Reset Your Password', // Override template subject
message_data: {
reset_link: 'https://app.example.com/reset/token123',
expiry_hours: 24
}
});
Order Confirmation (Raw HTML)
await client.sendEmail({
to: '[email protected]',
identifiers: { email: '[email protected]' },
from: '[email protected]',
reply_to: '[email protected]',
subject: 'Order Confirmation #12345',
body: `
<html>
<body>
<h1>Order Confirmed!</h1>
<p>Thank you for your order #12345</p>
<p>Total: $99.99</p>
</body>
</html>
`,
body_plain: 'Order Confirmed! Thank you for your order #12345. Total: $99.99'
});
Identifiers
You must provide exactly ONE of these identifier types:
// Using internal user ID (recommended)
identifiers: { id: 'user123' }
// Using email address
identifiers: { email: '[email protected]' }
The identifier must match the one used in identify(). See Consistent Identifiers for best practices.
You cannot provide multiple identifiers. The SDK will throw an error if you try.
// ❌ Error: Must contain exactly one identifier
identifiers: {
id: 'user123',
email: '[email protected]'
}
// ✅ Correct
identifiers: { id: 'user123' }
Attachments
Attach up to 5 files (2 MB decoded in total) with SendEmailRequest.attach(). Buffers are base64-encoded for you:
import { readFileSync } from 'fs';
import { SendEmailRequest } from '@codematic.io/cdp-node';
const request = new SendEmailRequest({
to: '[email protected]',
identifiers: { id: 'user123' },
transactional_message_id: 'INVOICE_EMAIL',
});
request.attach('invoice.pdf', readFileSync('./invoice.pdf'));
request.attach('notes.txt', 'Plain text content'); // strings are base64-encoded by default
request.attach('report.csv', existingBase64, { encode: false }); // already base64, sent as-is
await client.sendEmail(request);
You can also pass attachments directly as a map of filename to base64 content. The SDK validates attachments before sending: at most 5 files, at most 2 MB decoded in total, filenames without /, \ or .., and non-empty base64 content. The content type is inferred from the file extension.
Unsupported Fields Warning
Some fields are accepted by the API but not yet processed by the backend. The SDK will log a warning when you use them:
send_at- Scheduled send timesend_to_unsubscribed- Send to unsubscribed userstracked- Email trackingdisable_css_preprocessing- CSS preprocessing controlheaders- Custom email headersdisable_message_retention- Message retention controlqueue_draft- Queue as draftbcc- BCC recipientsfake_bcc- Fake BCCreply_to- Reply-to addresspreheader- Email preheader text
// This will log a warning about unsupported fields
await client.sendEmail({
to: '[email protected]',
identifiers: { id: 'user123' },
transactional_message_id: 'TEST',
subject: 'Test Email',
send_at: Math.floor(Date.now() / 1000) + 3600, // ⚠️ Warning logged
tracked: true, // ⚠️ Warning logged
headers: { 'X-Custom-Header': 'value' } // ⚠️ Warning logged
});
These fields are included for future compatibility but currently have no effect on email delivery.
Validation
The SDK validates your request before sending:
// ❌ Error: to is required
await client.sendEmail({
identifiers: { id: 'user123' },
transactional_message_id: 'WELCOME'
});
// ❌ Error: Invalid email address format
await client.sendEmail({
to: 'invalid-email',
identifiers: { id: 'user123' },
transactional_message_id: 'WELCOME'
});
// ❌ Error: body is required when not using a template
await client.sendEmail({
to: '[email protected]',
identifiers: { id: 'user123' },
from: '[email protected]',
subject: 'Test'
// Missing body!
});
// ✅ Valid template-based email
await client.sendEmail({
to: '[email protected]',
identifiers: { id: 'user123' },
transactional_message_id: 'WELCOME'
});
// ✅ Valid raw email
await client.sendEmail({
to: '[email protected]',
identifiers: { id: 'user123' },
from: '[email protected]',
subject: 'Test',
body: '<p>Test email</p>'
});
Error Handling
The SDK throws CDPEmailError with detailed information:
try {
const response = await client.sendEmail({
to: '[email protected]',
identifiers: { id: 'user123' },
transactional_message_id: 'WELCOME_EMAIL'
});
console.log('Email sent:', response);
} catch (error) {
console.error('Email send failed:', {
name: error.name, // 'CDPEmailError'
code: error.code, // 'EMAIL_SEND_FAILED'
message: error.message, // Error description
status: error.status, // HTTP status code
summary: error.summary // Detailed error summary
});
// Handle specific errors
if (error.status === 401) {
console.error('Invalid API key');
} else if (error.status === 404) {
console.error('Template not found');
} else if (error.status === 429) {
console.error('Rate limit exceeded');
}
}
Dual-Write Behavior
Unlike identify() and track(), emails are NOT forwarded to Customer.io even when dual-write is enabled. This prevents duplicate emails.
If sendToCustomerIo is true, you'll see this warning:
[CDP] Warning: Transactional messaging email will NOT be sent to Customer.io
to avoid sending twice. To turn this warning off set `sendToCustomerIo` to false.
Using SendEmailRequest Class
For advanced use cases, you can use the SendEmailRequest class:
import { SendEmailRequest } from '@codematic.io/cdp-node';
const request = new SendEmailRequest({
to: '[email protected]',
identifiers: { id: 'user123' },
transactional_message_id: 'WELCOME',
message_data: { name: 'John' }
});
// Add an attachment (Buffers are base64-encoded for you)
request.attach('invoice.pdf', pdfBuffer);
await client.sendEmail(request);
Related
- sendPush() - Send push notifications
- identify() - Identify users
- Email Examples
- Error Handling Guide