1. Context
  2. Message Service

Context

Message Service

The Messaging provides a unified API for sending messages through different transport channels. It abstracts the complexity of various messaging systems and provides a consistent interface for sending emails, SMS, webhooks, and other types of messages.

Configuration

SMTP Transport

The SMTP transport enables sending emails through any SMTP server:

[messaging.transports.smtp]
# SMTP server endpoint (required)
endpoint = "smtp://smtp.example.com:587"
# Use smtps:// for secure connections: "smtps://smtp.gmail.com:465"

# Authentication (optional for servers that require auth)
username = "your-username"
credentials = "your-password"

# Default sender address (optional)
defaultFrom = "[email protected]"

# Connection timeout in milliseconds (default: 60000)
timeout = 60000

# Force secure connection (optional, overridden by endpoint protocol)
secure = true

# TLS options (optional)
[message.transports.smtp.tls]
rejectUnauthorized = true

Configuration Examples

Gmail with App Password:

[messaging.transports.smtp]
endpoint = "smtps://smtp.gmail.com:465"

username = "[email protected]"
credentials = "your-app-password"
defaultFrom = "Your Company <[email protected]>"

Local Development (Mailhog/MailCatcher):

[messaging.transports.smtp]
endpoint = "smtp://localhost:1025"
# No auth required for local development servers

Usage

Basic Email

export const sendWelcomeEmail = async (source, args, context) => {
	const { userId } = args;
	const user = await context.ldap.findUserById(userId);

	const result = await context.messaging.send({
		transport: 'smtp',
		to: user.mail,
		subject: 'Welcome to our platform!',
		html: '<h1>Welcome!</h1><p>Thank you for joining us.</p>',
		text: 'Welcome! Thank you for joining us.', // Optional fallback
	});

	if (!result.success) {
		throw new Error(`Failed to send email: ${result.error}`);
	}

	return { success: true, messageId: result.messageId };
};

Multiple Recipients

const result = await context.messaging.send({
	transport: 'smtp',
	to: ['[email protected]', '[email protected]'],
	cc: '[email protected]',
	bcc: ['[email protected]', '[email protected]'],
	subject: 'Team Notification',
	html: '<p>Important team update...</p>',
});

Named Email Addresses

const result = await context.messaging.send({
	transport: 'smtp',
	to: '"John Doe" <[email protected]>',
	from: '"Support Team" <[email protected]>',
	subject: 'Personal Message',
	html: '<p>Hello John!</p>',
});

Email with Attachments

const result = await context.messaging.send({
	transport: 'smtp',
	to: '[email protected]',
	subject: 'Document Delivery',
	html: '<p>Please find the attached documents.</p>',
	attachments: [
		{
			filename: 'report.pdf',
			content: reportBuffer, // Buffer or base64 string
			contentType: 'application/pdf',
		},
		{
			filename: 'data.json',
			content: JSON.stringify(data),
			contentType: 'application/json',
		},
	],
});

Automatic HTML-to-Text Conversion

When you provide only HTML content, the service automatically generates a plain text version:

const result = await context.messaging.send({
	transport: 'smtp',
	to: '[email protected]',
	subject: 'Rich Content Email',
	html: `
    <h1>Welcome!</h1>
    <p>Visit our <a href="https://example.com">website</a></p>
    <ul>
      <li>Feature 1</li>
      <li>Feature 2</li>
    </ul>
  `,
	// No text field - automatically generated as:
	// "WELCOME!\n\nVisit our website [https://example.com]\n\n* Feature 1\n* Feature 2"
});

API Reference

Messaging Methods

send(message: Message): Promise<MessageResult>

Sends a message through the specified transport.

Parameters:

  • message: Message object with transport-specific properties

Returns:

  • MessageResult: Object containing success status, timestamp, messageId, and optional error

getAvailableTransports(): Transport[]

Returns a list of configured transports (without sensitive configuration data).

Returns:

  • Array of Transport objects with name and sanitized config

Message Types

SMTP Message

interface SMTPMessage {
	transport: 'smtp';
	to: string | string[]; // Recipients
	from?: string; // Sender (uses defaultFrom if not provided)
	subject: string; // Email subject
	text?: string; // Plain text content
	html?: string; // HTML content
	cc?: string | string[]; // Carbon copy recipients
	bcc?: string | string[]; // Blind carbon copy recipients
	attachments?: Array<{
		filename: string;
		content: string | Buffer;
		contentType?: string;
	}>;
}

Message Result

interface MessageResult {
	transport: string; // Transport used
	success: boolean; // Whether message was sent successfully
	sentAt?: Date; // Date object of send attempt if successful
	messageId?: string; // Unique message identifier (if successful)
	error?: string; // Error description (if failed)
}

Error Handling

The Messaging provides consistent error handling across all transports:

const result = await context.messaging.send(message);

if (!result.success) {
	console.error(`Message failed: ${result.error}`);
	// Handle error appropriately
	throw new Error(`Failed to send notification: ${result.error}`);
}

console.log(`Message sent successfully with ID: ${result.messageId}`);

Common Error Scenarios

  • Transport not configured: Returns error when specified transport is not available
  • Authentication failure: SMTP authentication errors
  • Network issues: Connection timeouts or server unavailability
  • Validation errors: Invalid email addresses or missing required fields

Best Practices

1. Configuration Management

Store sensitive credentials securely and use environment variables:

[messaging.transports.smtp]
endpoint = "smtp://smtp.example.com:587"
username = "${SMTP_USERNAME}"
credentials = "${SMTP_PASSWORD}"

2. Error Handling

Always check the result and handle failures appropriately:

const result = await context.messaging.send(message);
if (!result.success) {
	// Log error for debugging
	console.error('Failed to send message:', result.error);

	// Decide whether to throw or handle gracefully
	if (isRequired) {
		throw new Error(`Critical notification failed: ${result.error}`);
	}
}

3. Content Formatting

Provide both HTML and text versions for better compatibility:

const message = {
	transport: 'smtp',
	to: user.email,
	subject: 'Notification',
	html: '<h1>Hello!</h1><p>This is a <strong>rich</strong> message.</p>',
	text: 'Hello!\n\nThis is a rich message.',
};

4. Performance Considerations

For bulk messaging, consider queuing or rate limiting:

// For multiple recipients, consider sending individual messages
// to avoid delivery issues affecting all recipients
for (const recipient of recipients) {
	const result = await context.messaging.send({
		transport: 'smtp',
		to: recipient.email,
		subject: `Personal message for ${recipient.name}`,
		html: generatePersonalizedContent(recipient),
	});

	if (!result.success) {
		console.warn(`Failed to send to ${recipient.email}: ${result.error}`);
	}
}

Future Transports

The Messaging is designed to support additional transports:

  • SMS: Text messaging via Twilio, AWS SNS, etc.
  • Webhooks: HTTP POST notifications to external systems
  • Slack/Teams: Direct integration with chat platforms
  • Push Notifications: Mobile and web push notifications

Each transport will follow the same consistent API pattern while providing transport-specific configuration options.