
Security News
GitHub Actions Checkout Now Blocks Risky pull_request_target Checkouts
GitHub Actions checkout now blocks risky pull_request_target checkouts by default to help prevent pwn request supply chain attacks.
@semantq/mail
Advanced tools
Lightweight, Auto-Configuring Email Service for semantq full stack (semantqQL) Projects
Effortlessly send emails from your semantqQL applications with zero boilerplate. Auto-configures from your existing server.config.js, providing both simple and advanced emailing sending APIs.
npm install @semantq/mail
Add email configuration to your existing semantqQL/server.config.js:
export default {
// ... your existing database, server config
email: {
driver: 'resend', // 'resend' | 'sendgrid' | 'smtp' | 'log'
resend_api_key: process.env.RESEND_API_KEY,
sendgrid_api_key: process.env.SENDGRID_API_KEY,
email_from: process.env.EMAIL_FROM || 'noreply@example.com',
email_from_name: process.env.EMAIL_FROM_NAME || 'Our Team'
},
brand: {
name: process.env.BRAND_NAME || 'My App',
support_email: process.env.BRAND_SUPPORT_EMAIL || 'support@example.com'
}
};
Create a complete email service with one command:
# Generate Welcome email service
semantq make:mail Welcome
# Creates these files:
# - semantqQL/services/WelcomeService.js
# - semantqQL/mail/templates/welcome/welcome.js
# - semantqQL/mail/test-welcomeMail.js
Focus on this file: semantqQL/mail/test-welcomeMail.js
This is your starting template. Copy the email payload from here and customize it for your actual use case. The file contains complete examples for both basic and full-featured emails.
// In your actual application (anywhere in your codebase)
import welcomeMail from './services/WelcomeService.js'; // Adjust path as needed
const emailData = {
recipients: ['user@example.com','anotherUser@example.com'], // Required: recipient emails
subject: 'Basic Welcome Test', // Required: email subject (customise)
template: 'welcome/welcome', // Required: template path (folder/filename) (leave as is)
recipient: { // Optional: recipient details for personalization
email: 'user@example.com',
name: 'User Name' // Shows as "Hi User Name,"
},
text: 'This is your email content.' // Content: Use text, html, OR body
};
await welcomeMail.sendWelcome(emailData);
// 1. Plain text
text: 'Simple text message'
// 2. HTML content
html: '<h2>Styled HTML</h2><p>With <strong>formatting</strong></p>'
// 3. Simple body (auto-detects HTML/text)
body: 'Can be plain text or HTML'
const fullOptions = {
recipients: ['customer@example.com', 'backup@example.com'],
subject: 'Complete Order Details',
template: 'orders/confirmation',
recipient: {
email: 'customer@example.com',
name: 'John Smith'
},
// Content options (choose one):
text: 'Plain text content here',
// OR html: '<p>HTML content here</p>',
// OR body: 'Simple content here',
// Optional features:
cc: ['team@example.com'],
bcc: ['analytics@example.com'],
replyTo: 'support@example.com',
from: 'noreply@example.com',
fromName: 'Your Company',
attachments: [
{
filename: 'invoice.pdf',
content: 'base64String',
contentType: 'application/pdf'
}
],
templateData: { // Optional template variables
themeColor: '#4CAF50', // Changes button colors
orderNumber: '12345',
orderDate: '2024-12-10'
}
};
The generated test script assumes you're running from semantqQL directory. If you're calling emails from elsewhere:
// If running from project root:
import welcomeMail from './semantqQL/services/WelcomeService.js';
// If running from other directories:
import welcomeMail from '../services/WelcomeService.js';
// If your service is in a different location:
import welcomeMail from '../../path/to/services/WelcomeService.js';
Pro Tip: Test your import path by running the generated test script first:
cd semantqQL
node mail/test-welcomeMail.js
Once the test works, copy the payload structure to your actual application code.
A. Service File (semantqQL/services/WelcomeService.js)
import { MailService } from '@semantq/mail';
class WelcomeService {
constructor() {
this.mail = new MailService();
}
async sendWelcome(user, options = {}) {
return this.mail.send({
to: user.email,
subject: `Welcome to ${this.mail.config.brand?.name}!`,
template: 'welcome',
templateData: { name: user.name, ...options }
});
}
}
export default new WelcomeService();
B. Content Template (semantqQL/mail/templates/welcome/welcome.js)
// Welcome Email Template
// This template returns EMPTY content since content comes from payload
export default {
subject: ({ data, brand }) => {
return data.subject || `Message from ${brand?.name || 'Our Service'}`;
},
html: ({ data, recipient, brand }) => {
// Content comes from payload (text, html, or body fields)
return '';
},
text: ({ data, recipient, brand }) => {
return '';
}
};
C. Test Script (semantqQL/mail/test-welcomeMail.js)
// test-welcomeMail.js
// Minimal test script for Welcome email service
// Run: cd semantqQL && node mail/test-welcomeMail.js
import welcomeMail from '../services/WelcomeService.js';
async function testWelcomeMailEmail() {
try {
// 1. Initialize service
await welcomeMail.init();
console.log('[STATUS] Service ready | Driver: ' + welcomeMail.mail?.getDriverName());
// ============================================
// CONFIGURATION: EDIT EMAIL ADDRESS BELOW
// ============================================
// BASIC EXAMPLE - Simple text email
const emailData = {
recipients: ['test@example.com'], // <--- Replace with your email
subject: 'Basic Welcome Test',
template: 'welcome/welcome',
recipient: {
email: 'test@example.com',
name: 'Test User'
},
text: 'This is a test email from the Welcome service.'
};
// ============================================
// CORE FUNCTION: DO NOT ALTER CORE CODE HERE
// ============================================
console.log('\n[SENDING] Dispatching email...');
const result = await welcomeMail.sendWelcome(emailData);
if (result.success) {
console.log('[RESULT] Basic test: PASS');
} else {
console.log(`[RESULT] Basic test: FAILED TEST - ${result.message || 'Unknown Error'}`);
}
return result.success;
} catch (error) {
console.error('\n[ERROR] Setup/Runtime Failure:', error.message);
return false;
}
}
// Run test
testWelcomeMailEmail()
.then(success => {
process.exit(success ? 0 : 1);
})
.catch(() => {
process.exit(1);
});
Edit services/WelcomeService.js to add custom logic:
// Add custom methods
class WelcomeService {
constructor() {
this.mail = new MailService();
}
async sendWelcome(user) {
return this.mail.send({
recipients: [user.email],
subject: `Welcome to ${this.mail.config.brand?.name}!`,
template: 'welcome/welcome',
recipient: {
email: user.email,
name: user.fullName
},
text: `Welcome ${user.fullName}! We're excited to have you on board.`
});
}
async sendPasswordReset(user, resetUrl) {
return this.mail.send({
recipients: [user.email],
subject: 'Reset Your Password',
template: 'auth/password-reset',
recipient: {
email: user.email,
name: user.firstName
},
html: `
<h2>Password Reset</h2>
<p>Click the link below to reset your password:</p>
<a href="${resetUrl}">Reset Password</a>
`
});
}
}
Content comes from text, html, or body fields in your payload:
// Plain text email
const emailData = {
recipients: ['user@example.com'],
subject: 'Basic Email',
template: 'welcome/welcome',
recipient: { email: 'user@example.com', name: 'John' },
text: 'This is a plain text message.'
};
// HTML email
const emailData = {
recipients: ['user@example.com'],
subject: 'Styled Email',
template: 'welcome/welcome',
recipient: { email: 'user@example.com', name: 'John' },
html: `
<h2>Welcome John!</h2>
<p>This is a custom HTML email with styling.</p>
<a href="https://example.com" style="color: #007bff;">Visit Website</a>
`
};
// Using templateData for additional variables
const emailData = {
recipients: ['user@example.com'],
subject: 'Order Confirmation',
template: 'orders/confirmation',
recipient: { email: 'user@example.com', name: 'John' },
text: 'Your order #123 has been confirmed.',
templateData: {
orderNumber: '123',
orderDate: '2024-12-10',
themeColor: '#4CAF50' // Customizes button colors
}
};
{
// REQUIRED fields
recipients: ['user@example.com'],
subject: 'Email Subject',
template: 'template-name',
// OPTIONAL content (use one)
text: 'Plain text content',
html: '<p>HTML content</p>',
body: 'Simple text or HTML',
// OPTIONAL recipient info
recipient: {
email: 'user@example.com',
name: 'User Name'
},
// OPTIONAL template data
templateData: {
themeColor: '#007bff',
customField: 'Any data'
},
// OPTIONAL email routing
cc: ['team@example.com'],
bcc: ['archive@example.com'],
replyTo: 'support@example.com',
from: 'noreply@example.com',
fromName: 'Your Brand',
// OPTIONAL attachments
attachments: [
{
filename: 'document.pdf',
content: 'base64String',
contentType: 'application/pdf'
}
]
}
const fullOptions = {
// REQUIRED: Core email fields
recipients: ['customer@example.com', 'backup@example.com'],
subject: 'Full Featured Email',
template: 'template-name',
// OPTIONAL: Content (use one or more)
text: 'Plain text version of the email',
html: '<p>HTML <strong>version</strong> of the email</p>',
// OPTIONAL: Recipient info
recipient: {
email: 'customer@example.com',
name: 'Customer Name'
},
// OPTIONAL: Email routing
cc: ['team@example.com'],
bcc: ['analytics@example.com'],
replyTo: 'support@example.com',
from: 'noreply@example.com',
fromName: 'Your Team',
// OPTIONAL: Attachments
attachments: [
{
filename: 'test.txt',
content: 'This is a test attachment',
contentType: 'text/plain'
}
],
// OPTIONAL: Additional template data
templateData: {
features: ['Feature 1', 'Feature 2'],
customField: 'Any data you need',
themeColor: '#667eea'
}
};
# Run the generated test script
cd semantqQL
node mail/test-welcomeMail.js
# Output:
# [STATUS] Service ready | Driver: resend
# [SENDING] Dispatching email...
# [RESULT] Basic test: PASS
Create a template that generates content:
// semantqQL/mail/templates/welcome/custom-welcome.js
export default {
subject: ({ data, brand }) => {
return data.subject || `Welcome to ${brand?.name}`;
},
html: ({ data, recipient, brand }) => {
const recipientName = recipient?.name || 'there';
return `
<div>
<h2>Welcome ${recipientName}!</h2>
<p>Thank you for joining ${brand?.name}.</p>
${data.customMessage ? `<p>${data.customMessage}</p>` : ''}
</div>
`;
},
text: ({ data, recipient, brand }) => {
const recipientName = recipient?.name || 'there';
return `Welcome ${recipientName}!\n\nThank you for joining ${brand?.name}.`;
}
};
// Usage
const emailData = {
recipients: ['user@example.com'],
subject: 'Welcome',
template: 'welcome/custom-welcome',
recipient: { email: 'user@example.com', name: 'John' },
templateData: {
customMessage: 'Check out our getting started guide!'
}
};
All emails use BaseLayout which provides:
Customize via templateData.themeColor:
templateData: {
themeColor: '#4CAF50' // Changes button and link colors
}
import { MailService } from '@semantq/mail';
const mail = new MailService();
// Send email
await mail.send({
recipients: ['user@example.com'],
subject: 'Test Email',
template: 'template-name',
text: 'Email content',
recipient: { email: 'user@example.com', name: 'User Name' }
});
// Check driver
console.log(mail.getDriverName()); // 'resend', 'sendgrid', 'smtp', or 'log'
// Check if using real driver
console.log(mail.isRealDriver()); // true for resend/sendgrid/smtp, false for log
When sending emails, content is determined in this order:
html field in payloadtext field in payloadbody field in payload// Resend (Recommended)
email: {
driver: 'resend',
resend_api_key: 're_xxxxxxxxxx',
email_from: 'noreply@example.com',
email_from_name: 'Your Brand'
}
// SendGrid
email: {
driver: 'sendgrid',
sendgrid_api_key: 'SG.xxxxxxxxxx'
}
// SMTP
email: {
driver: 'smtp',
smtp_host: 'smtp.gmail.com',
smtp_port: 587,
smtp_user: 'user@gmail.com',
smtp_pass: 'password'
}
// Log (Development)
email: {
driver: 'log'
}
brand: {
name: 'Your App Name',
support_email: 'support@example.com'
}
server.config.js has correct email configurationNODE_ENV is not forcing log driverEnsure recipient field includes both email and name:
recipient: {
email: 'someuser@example.com',
name: 'User Name' // Required for personalized greeting
}
Content must come from text, html, or body fields:
// WRONG - templateData.message won't show
templateData: { message: 'Hello' }
// CORRECT - use text, html, or body
text: 'Hello' // or
html: '<p>Hello</p>' // or
body: 'Hello'
Check template path matches structure:
// Template file: mail/templates/orders/confirmation.js
template: 'orders/confirmation' // folder/filename (no .js)
MIT © semantq Team
To DO:
FAQs
Lightweight email service for semantqQL projects
We found that @semantq/mail demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
GitHub Actions checkout now blocks risky pull_request_target checkouts by default to help prevent pwn request supply chain attacks.

Product
Socket now supports Custom Roles and Repository Access Permissions so organizations can control who can access specific repositories and actions.

Product
Socket MCP now lets AI assistants review org alerts, investigate threats using the Socket threat feed, and inspect package files in addition to dependency scoring.