|
|
|
@@ -1,6 +1,6 @@
|
|
|
|
# @push.rocks/smartmta
|
|
|
|
# @push.rocks/smartmta
|
|
|
|
|
|
|
|
|
|
|
|
A high-performance, enterprise-grade Mail Transfer Agent (MTA) built from scratch in TypeScript with a Rust-powered SMTP engine — no nodemailer, no shortcuts. 🚀
|
|
|
|
A high-performance, enterprise-grade Mail Transfer Agent (MTA) built from scratch in TypeScript with a Rust-powered SMTP engine — no nodemailer, no shortcuts. Automatic MX record discovery means you just call `sendEmail()` and smartmta figures out where to deliver. 🚀
|
|
|
|
|
|
|
|
|
|
|
|
## Issue Reporting and Security
|
|
|
|
## Issue Reporting and Security
|
|
|
|
|
|
|
|
|
|
|
|
@@ -78,9 +78,10 @@ After installation, run `pnpm build` to compile the Rust binary (`mailer-bin`).
|
|
|
|
|
|
|
|
|
|
|
|
**Data flow for outbound mail:**
|
|
|
|
**Data flow for outbound mail:**
|
|
|
|
|
|
|
|
|
|
|
|
1. 📝 TypeScript constructs the email and resolves DKIM keys for the sender domain
|
|
|
|
1. 📝 TypeScript constructs the email and calls `sendEmail()` (defaults to MTA mode)
|
|
|
|
2. 🦀 Sends to Rust via IPC — Rust builds the RFC 2822 message, signs with DKIM, and delivers via its SMTP client with connection pooling
|
|
|
|
2. 🔍 MTA mode automatically resolves MX records for each recipient domain, sorts by priority, and groups recipients for efficient delivery
|
|
|
|
3. 📬 Result (accepted/rejected recipients, server response) returned to TypeScript
|
|
|
|
3. 🦀 Sends to Rust via IPC — Rust builds the RFC 2822 message, signs with DKIM, and delivers via its SMTP client with connection pooling
|
|
|
|
|
|
|
|
4. 📬 Result (accepted/rejected recipients, server response) returned to TypeScript
|
|
|
|
|
|
|
|
|
|
|
|
## Usage
|
|
|
|
## Usage
|
|
|
|
|
|
|
|
|
|
|
|
@@ -169,9 +170,9 @@ await emailServer.start();
|
|
|
|
|
|
|
|
|
|
|
|
> 🔒 **Note:** `start()` will throw if the Rust binary is not compiled. Run `pnpm build` first.
|
|
|
|
> 🔒 **Note:** `start()` will throw if the Rust binary is not compiled. Run `pnpm build` first.
|
|
|
|
|
|
|
|
|
|
|
|
### 📧 Sending Outbound Emails
|
|
|
|
### 📧 Sending Emails (Automatic MX Discovery)
|
|
|
|
|
|
|
|
|
|
|
|
All outbound email delivery goes through the Rust SMTP client, accessed via `UnifiedEmailServer.sendOutboundEmail()`. The Rust client handles connection pooling, TLS negotiation, and DKIM signing automatically:
|
|
|
|
The recommended way to send email is `sendEmail()`. It defaults to **MTA mode**, which automatically resolves MX records for each recipient domain via DNS — you don't need to know the destination mail server:
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
```typescript
|
|
|
|
import { Email, UnifiedEmailServer } from '@push.rocks/smartmta';
|
|
|
|
import { Email, UnifiedEmailServer } from '@push.rocks/smartmta';
|
|
|
|
@@ -179,8 +180,7 @@ import { Email, UnifiedEmailServer } from '@push.rocks/smartmta';
|
|
|
|
// Build an email
|
|
|
|
// Build an email
|
|
|
|
const email = new Email({
|
|
|
|
const email = new Email({
|
|
|
|
from: 'sender@example.com',
|
|
|
|
from: 'sender@example.com',
|
|
|
|
to: ['recipient@example.com'],
|
|
|
|
to: ['alice@gmail.com', 'bob@company.org'],
|
|
|
|
cc: ['cc@example.com'],
|
|
|
|
|
|
|
|
subject: 'Hello from smartmta! 🚀',
|
|
|
|
subject: 'Hello from smartmta! 🚀',
|
|
|
|
text: 'Plain text body',
|
|
|
|
text: 'Plain text body',
|
|
|
|
html: '<h1>Hello!</h1><p>HTML body with <strong>formatting</strong></p>',
|
|
|
|
html: '<h1>Hello!</h1><p>HTML body with <strong>formatting</strong></p>',
|
|
|
|
@@ -194,7 +194,50 @@ const email = new Email({
|
|
|
|
],
|
|
|
|
],
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// Send via the Rust SMTP client (connection pooling, TLS, DKIM signing)
|
|
|
|
// Send — MTA mode auto-discovers MX servers for gmail.com and company.org
|
|
|
|
|
|
|
|
const emailId = await emailServer.sendEmail(email);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Optionally specify a delivery mode explicitly
|
|
|
|
|
|
|
|
const emailId2 = await emailServer.sendEmail(email, 'mta');
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
In MTA mode, smartmta:
|
|
|
|
|
|
|
|
- 🔍 Resolves MX records for each recipient domain (e.g. `gmail.com`, `company.org`)
|
|
|
|
|
|
|
|
- 📊 Sorts MX hosts by priority (lowest = highest priority per RFC 5321)
|
|
|
|
|
|
|
|
- 🔄 Tries each MX host in order until delivery succeeds
|
|
|
|
|
|
|
|
- 🌐 Falls back to the domain's A record if no MX records exist
|
|
|
|
|
|
|
|
- 📦 Groups recipients by domain for efficient batch delivery
|
|
|
|
|
|
|
|
- 🔑 Signs outbound mail with DKIM automatically
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 📮 Delivery Modes
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
`sendEmail()` accepts a mode parameter that controls how the email is delivered:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
|
|
public async sendEmail(
|
|
|
|
|
|
|
|
email: Email,
|
|
|
|
|
|
|
|
mode: EmailProcessingMode = 'mta', // 'mta' | 'forward' | 'process'
|
|
|
|
|
|
|
|
route?: IEmailRoute,
|
|
|
|
|
|
|
|
options?: {
|
|
|
|
|
|
|
|
skipSuppressionCheck?: boolean;
|
|
|
|
|
|
|
|
ipAddress?: string;
|
|
|
|
|
|
|
|
isTransactional?: boolean;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
): Promise<string>
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| Mode | Description |
|
|
|
|
|
|
|
|
|---|---|
|
|
|
|
|
|
|
|
| `mta` (default) | **Auto MX discovery** — resolves MX records via DNS, delivers directly to the recipient's mail server. No relay configuration needed. |
|
|
|
|
|
|
|
|
| `forward` | **Relay delivery** — forwards the email to a configured SMTP host (e.g. an internal mail gateway or third-party relay). |
|
|
|
|
|
|
|
|
| `process` | **Scan + deliver** — runs the content scanning / security pipeline first, then delivers via auto MX resolution. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 📬 Direct SMTP Delivery (Low-Level)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
For cases where you know the exact target SMTP server (e.g. relaying to a specific host), use the lower-level `sendOutboundEmail()`:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
|
|
// Send directly to a known SMTP server (bypasses MX resolution)
|
|
|
|
const result = await emailServer.sendOutboundEmail('smtp.example.com', 587, email, {
|
|
|
|
const result = await emailServer.sendOutboundEmail('smtp.example.com', 587, email, {
|
|
|
|
auth: { user: 'sender@example.com', pass: 'your-password' },
|
|
|
|
auth: { user: 'sender@example.com', pass: 'your-password' },
|
|
|
|
dkimDomain: 'example.com',
|
|
|
|
dkimDomain: 'example.com',
|
|
|
|
|