Agnostic transactional email sending in Node.js environment
To improve and facilitate the implementation, the flexibility and the maintenance of transactional emailing tasks.
- Agnostic transactional email sending using web API or SMTP server. One input, one output.
- Multiple simultaneous transporters.
- Configuration based, not implementation based: easy switch between different modes.
- Normalized transactions events.
- Securized payloads.
- Customisable default templates.
- Requirements
- Getting started
- Selective imports
- Beneficiary use cases
- Supported web API providers
- Upgrading to v3
- Licence
- Documentation
- Node.js >= 18.19.0
- NPM >= 10.2.3
> npm i cliam --saveCliam must be configured once at application startup, before any call to mail(). Two approaches are available.
Option A - Pass a configuration object directly:
import { Cliam } from 'cliam';
import type { IClientConfiguration } from 'cliam';
const config: IClientConfiguration = {
sandbox: true,
variables: {
addresses: {
from: { name: 'My App', email: 'no-reply@my-website.com' },
replyTo: { name: 'My App', email: 'no-reply@my-website.com' }
}
},
transporters: [
{
id: 'smtp-main',
auth: {
username: process.env.SMTP_USERNAME,
password: process.env.SMTP_PASSWORD
},
options: {
host: process.env.SMTP_HOST,
port: 587,
secure: false
}
},
{
id: 'sendgrid-api',
provider: 'sendgrid',
auth: {
apiKey: process.env.SENDGRID_API_KEY
},
templates: {
'user.welcome': 'd-321bb40f548e4db8a628b4d6464ebacc'
}
}
]
};
Cliam.configure(config);Option B - Load from a .cliamrc.js file:
import { Cliam } from 'cliam';
// Loads .cliamrc.js from process.cwd() by default
Cliam.configureFromFile();
// Or pass an explicit path
Cliam.configureFromFile('/path/to/my-cliam-config.js');The .cliamrc.js file should export the same configuration object as above:
require('dotenv').config();
module.exports = {
sandbox: true,
variables: {
addresses: {
from: { name: 'My App', email: 'no-reply@my-website.com' },
replyTo: { name: 'My App', email: 'no-reply@my-website.com' }
}
},
transporters: [ ... ]
};Use environment variables for sensitive values such as API keys. Cliam does not load .env automatically.
See cliamrc configuration wiki section for the full list of available options.
The default entry point registers all supported providers at import time:
import { Cliam } from 'cliam'; // all providers loadedIf you use a bundler and want to reduce your bundle size, import the core and load only the providers you actually use:
import { Cliam } from 'cliam/core';
import 'cliam/providers/sendgrid';
// import 'cliam/providers/smtp'; // add others as neededTypes and enums are available separately:
import type { IPayload, IClientConfiguration } from 'cliam/types';
import { EVENT, PROVIDER } from 'cliam/types';Available sub-paths:
| Sub-path | Exports |
|---|---|
cliam |
Cliam, SendingResponse, SendingError, all types - registers all providers |
cliam/core |
Cliam, SendingResponse, SendingError- no providers registered |
cliam/types |
All interfaces, enums and types - no runtime code |
cliam/providers/brevo |
Side-effect: registers the Brevo transporter |
cliam/providers/mailersend |
Side-effect: registers the Mailersend transporter |
cliam/providers/mailgun |
Side-effect: registers the Mailgun transporter |
cliam/providers/mailjet |
Side-effect: registers the Mailjet transporter |
cliam/providers/mandrill |
Side-effect: registers the Mandrill transporter |
cliam/providers/postmark |
Side-effect: registers the Postmark transporter |
cliam/providers/resend |
Side-effect: registers the Resend transporter |
cliam/providers/sendgrid |
Side-effect: registers the Sendgrid transporter |
cliam/providers/ses |
Side-effect: registers the Amazon SES transporter |
cliam/providers/sparkpost |
Side-effect: registers the Sparkpost transporter |
cliam/providers/smtp |
Side-effect: registers the SMTP transporter |
If a transporter is configured but its provider was never imported, Cliam throws at send time with a clear message.
import { Cliam } from 'cliam';
import type { IPayload } from 'cliam';
const payload: IPayload = {
meta: {
from: { email: 'john.doe@hotmail.com', name: 'John Doe' },
to: [{ email: 'john.allan.poe@hotmail.com' }],
replyTo: { email: 'john.doe@hotmail.com', name: 'John Doe' },
subject: 'Welcome John'
},
content: [
{
type: 'text/html',
value: '<h1>Hello Yoda</h1><p>I use Cliam to send my emails !</p>'
}
]
};
Cliam.mail('user.welcome', payload)
.then(res => {
console.log('Email delivered: ', res);
})
.catch(err => {
console.log('Error: ', err);
});The render engine is inferred automatically:
contentprovided → uses your HTML directly- No
content, template ID configured for the event → delegates to the provider's template engine - No
content, no template → uses Cliam's built-in default templates
By default, Cliam uses the first transporter in the configuration. Pass transporterId in the payload to target a specific one.
See email payload wiki section for the full payload reference.
✅ I have many projects which uses differents providers, it's a hell of a thing to maintain.
This is to be forgotten with Cliam. No more worries about polymorphics inputs / outputs. Whether you are working with an A, B, C, D provider or a smtp server, your input / output will always be the same regardless of your delivery method or service provider.
✅ I'm just using many providers into a same project, it's convoluted to securize and maintain.
Same purpose. Whether you are working with a provider or a SMTP server - or boths, with Cliam, you don't get anymore n libraries into your node_modules folder: we only embed the bare metal minimum, and not some old deprecated SDK's.
✅ I wish change from supplier, but I'm afraid about the implementation ?
Without Cliam, indeed you could be. With, your implementation does not move, you just have to adapt a configuration when you want to change your method. Remove your legacy code, and embrace simplicity through Cliam.
✅ I don't have a subscription to a supplier, and no templates
No problem, we have all been poor once. Start with a simple SMTP server and use default templates. When your business is up, you can use a paid web api.
✅ I have a big problem with a provider, and my emails stay blocked in the pipe !
The same: fallback on a SMTP server or another provider. In two minutes you're ready and your mailing is back in operation.
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |










