Overview
Loopar includes a built-in email service — loopar.mail — backed by Nodemailer. It handles SMTP delivery, reusable templates, a persistent send queue with automatic retries, and a ready-to-use contact form element. No third-party email SDK required.
| Capability | Method(s) |
|---|---|
| Send now | loopar.mail.send() |
| Send a template | loopar.mail.sendTemplate() |
| Queue for background delivery | loopar.mail.queue(), queueBulk() |
| Operate the queue | processQueue(), getQueueStats(), retryFailed(), cancelPending() |
| Maintenance | cleanOldEmails(), testConnection(), previewTemplate() |
Configuration
SMTP settings live in the Email Settings document (a Single entity). Configure it from the Desk:
| Field | Description |
|---|---|
host / port | SMTP server address and port |
secure | Use TLS (1 = on) |
auth_enabled | Whether the server requires authentication |
user / password | SMTP credentials |
timeout | Connection timeout in milliseconds |
max_connections | Pooled connection limit |
rate_limit | Max messages per second |
debug | Verbose SMTP logging |
The transporter is pooled and created lazily on the first send, so settings changes take effect on the next process restart.
Sending Email
Send Immediately
import loopar from "loopar";
await loopar.mail.send({
to: "customer@example.com",
subject: "Welcome aboard",
html: "<h1>Welcome!</h1><p>Thanks for joining.</p>",
text: "Welcome! Thanks for joining.", // optional plain-text part
cc: ["manager@example.com"], // optional
bcc: ["archive@example.com"], // optional
replyTo: "support@example.com", // optional
attachments: [ // optional
{ filename: "guide.pdf", path: "/path/to/guide.pdf" }
]
});
send() delivers synchronously and throws on failure. For anything non-critical, prefer the queue.
Templates
Store reusable email bodies as templates and render them with variables:
await loopar.mail.sendTemplate({
template: "welcome",
to: "customer@example.com",
variables: { name: "John", plan: "Pro" }
});
Preview a rendered template without sending it:
const html = await loopar.mail.previewTemplate("welcome", { name: "John" });
Templates are cached after first load for fast repeated sends.
The Send Queue
For transactional mail that shouldn't block a request, queue it. Queued messages are persisted, prioritized, and retried automatically.
// Queue a single message
await loopar.mail.queue({
to: "customer@example.com",
subject: "Your invoice",
html: invoiceHtml,
priority: "High" // Urgent | High | Normal | Low
});
// Queue many at once
await loopar.mail.queueBulk(messages, { priority: "Normal" });
Processing & Monitoring
await loopar.mail.processQueue(10); // send up to 10 pending items
const stats = await loopar.mail.getQueueStats();
await loopar.mail.retryFailed(); // retry failed messages
await loopar.mail.cancelPending(ids); // cancel queued messages
await loopar.mail.cleanOldEmails(30); // prune entries older than 30 days
Failed messages back off through escalating retry delays before being marked as failed.
Contact Form
For public pages, Loopar ships a drag-and-drop contact_form element that wires straight into the email service — no controller code needed.
{
"element": "contact_form",
"data": {
"label": "Contact us",
"to": "sales@example.com"
}
}
Drop it onto any page in the Page Builder, point it at a recipient, and submissions are delivered (or queued) through loopar.mail. Spam submissions are filtered out before they reach your inbox.