Skip to content

Send Email to Specific Contacts

Send email messages to a specific list of email addresses. The operation is asynchronous: the API records every message in persistence, schedules delivery in BullMQ, and returns an enqueue summary.

  • Include the bearer token in Authorization: Bearer <token>.
  • Only members that accepted the current terms can trigger messaging actions; otherwise the service returns 403 Forbidden.
interface EmailContactsMessagePayload extends EmailMessageBasePayload {
contacts: string[]; // Explicit list of email addresses
}
interface EmailMessageBasePayload {
subject: string;
message: string; // HTML or plain text supported by the provider
}
FieldTypeRequiredDescription
subjectstringYesEmail subject
messagestringYesEmail content (HTML or plain text)
contactsstring[]YesList of email addresses
{
"subject": "Welcome to SendMe - Registration Confirmation",
"message": "<h1>Welcome!</h1><p>Your account has been successfully created. Thank you for joining SendMe.</p>",
}

The API responds with the shared MessageEnqueueResultDto contract:

interface MessageEnqueueResultDto {
queueId: string; // BullMQ job identifier, empty when nothing was enqueued
channel: 'email';
messages: Array<{
id: string; // UUID of the persisted message
recipient: string; // Email address normalized by the backend
}>;
}
{
"queueId": "email-queue-12345",
"channel": "email",
"messages": [
{
"id": "msg-uuid-1",
"recipient": "[email protected]"
},
{
"id": "msg-uuid-2",
"recipient": "[email protected]"
}
]
}

When the request does not resolve any valid email addresses, the service responds with 200 OK, an empty queueId, and an empty messages array.

{
"queueId": "",
"channel": "email",
"messages": []
}
async function sendEmailToContacts(token: string, payload: EmailContactsMessagePayload) {
const response = await fetch('/api/messages/email/contacts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
},
body: JSON.stringify(payload),
});
if (!response.ok) {
throw new Error(`Email enqueue failed: ${response.status}`);
}
const data: MessageEnqueueResultDto = await response.json();
return data;
}
// Usage with HTML
const result = await sendEmailToContacts('your-token', {
subject: 'Invoice for your order #12345',
message: `
<div style="font-family: Arial, sans-serif;">
<h2>Thank you for your purchase</h2>
<p>Attached you will find the invoice for your order.</p>
<a href="#" style="background: #007cba; color: white; padding: 10px 20px; text-decoration: none;">
View Order
</a>
</div>
`,
contacts: ['[email protected]']
});
console.log(`Emails enqueued: ${result.messages.length}`);
const htmlPayload = {
subject: "Special Promotion",
message: `
<html>
<body>
<div style="max-width: 600px; margin: 0 auto;">
<h1 style="color: #333;">Special Offer!</h1>
<p>Don't miss our end-of-season promotion.</p>
<img src="https://example.com/promotion.jpg" alt="Promotion" style="max-width: 100%;">
<a href="https://store.example.com" style="background: #ff6b6b; color: white; padding: 15px 25px; text-decoration: none; border-radius: 5px;">
Shop Now
</a>
</div>
</body>
</html>
`,
contacts: ["[email protected]"]
};
const textPayload = {
subject: "Appointment Confirmation",
message: `
Dear Customer,
Your appointment has been confirmed for:
Date: April 15, 2024
Time: 10:00 AM
Location: Main Office
If you need to reschedule, please reply to this email.
Best regards,
SendMe Team
`,
contacts: ["[email protected]"]
};
  • The backend removes duplicated recipients per batch and silently skips invalid destinations.
  • Balance validation runs before queuing; insufficient credits return an error response without enqueuing messages.
  • Use the returned queueId to correlate delivery status inside the admin UI or via dedicated status endpoints.
  • Each message persists provider metadata and can be audited through the messaging module filters.
  • HTML content must be valid and compatible with major email clients.