
Company News
Socket Joins New OpenJS Program to Fund Node.js Security Work
Socket is joining the OpenJS Security Stewardship Program to fund Node.js vulnerability research, maintainer remediation, and security releases.
@strav/mail
Advanced tools
Strav signal layer — mail (core + array/log transports + Mailable + queue-dispatch); notifications + SSE + broadcast follow in later slices
Outbound communication for Strav 1.0. Mail layer covers sync send + queued delivery + three production HTTP transports:
Message + MailRecipient + MailAddress + MessageAttachment — the plain-data envelope.Transport interface — what every backend implements (send, optional close).ArrayTransport — in-memory recorder for tests.LogTransport — writes mail.sent records to a Logger channel; local-dev default.ResendTransport + SendGridTransport + MailgunTransport + AlibabaDmTransport — production HTTP transports. Pure-fetch, no SDK deps, no nodemailer. Alibaba Cloud DirectMail covers China + SEA deliverability.MailTransportError — typed StravError raised by transports on send failure; carries provider / status / retryable / providerError in context.PostmarkInboundParser + MailgunInboundParser — normalize provider webhooks to ParsedInboundMail. Mailgun verifies HMAC-SHA256 + timestamp; Postmark relies on HTTP-level auth (Basic / IP allow-list).isAutoGeneratedMessage — mail-loop guard. Honour it before auto-responding.MailInboundError — raised when an inbound webhook payload is malformed.MailManager — multi-transport orchestration with default-from substitution + Mailable-aware send overload + lazy/cached transport build.MailProvider — wires config.mail into the container.Mailable<TPayload> — typed Job subclass; override build(payload), dispatch via queue.dispatch(YourMailable, payload) for async delivery with retries / dead-letter.Status: 1.0.0-alpha — outbound mail layer + Resend + SendGrid + Mailgun + Alibaba DirectMail transports shipped, plus Postmark + Mailgun inbound webhook parsers. Multi-channel fan-out lives in
@strav/notification. No SMTP transport — seedocs/mail/README.mdfor the rationale.
bun add @strav/mail
Peer: @strav/kernel.
// config/mail.ts
import type { MailConfig } from '@strav/mail'
export default {
default: 'array', // or 'log' in dev, 'smtp' once it ships
from: { email: 'noreply@acme.com', name: 'Acme' },
transports: {
array: { driver: 'array' },
log: { driver: 'log', channel: 'mail' },
},
} satisfies MailConfig
// in a controller or service
@inject()
class SignupController {
constructor(private readonly mail: MailManager) {}
async send(email: string): Promise<void> {
await this.mail.send({
to: email,
subject: 'Welcome',
html: '<h1>Welcome</h1>',
text: 'Welcome',
})
}
}
await mail.send({ to: 'a@x', subject: 'hi', text: 'h' })
expect((mail.via() as ArrayTransport).messages[0]?.subject).toBe('hi')
ArrayTransport.messages is a frozen view of every send since the last clear().
import { Mailable, type Message } from '@strav/mail'
class WelcomeEmail extends Mailable<{ name: string }> {
static override readonly jobName = 'mail.welcome'
build(payload: { name: string }): Message {
return { to: `${payload.name}@x`, subject: 'Welcome', text: `Hi ${payload.name}` }
}
}
// Register with JobRegistry (same as any other Job).
registry.register(WelcomeEmail)
// Dispatch:
await queue.dispatch(WelcomeEmail, { name: 'Alice' }) // async, retried
await mail.send(WelcomeEmail, { name: 'Alice' }) // sync, inline
Mailables participate in the full @strav/queue lifecycle (retries, backoff, strav_failed_jobs dead-letter).
import { MailgunInboundParser, PostmarkInboundParser } from '@strav/mail'
const postmark = new PostmarkInboundParser()
const mailgun = new MailgunInboundParser({ webhookSigningKey: env.MAILGUN_SIGNING_KEY })
// In your HTTP handler — pass the raw body + lowercased headers:
const mail = await mailgun.parse({ body: rawBody, headers: req.headers })
if (mail.isAutoGenerated) return // mail-loop guard — must honor.
await onIncoming(mail)
The parsed shape (ParsedInboundMail) is identical across providers: from/to/cc/bcc, subject/text/html, RFC-5322 messageId / inReplyTo / references, decoded attachments as Buffer, and isAutoGenerated derived from Auto-Submitted / Precedence / X-Auto-Response-Suppress.
@strav/notification).Full reference: docs/mail/api.md.
FAQs
Strav signal layer — mail (core + array/log transports + Mailable + queue-dispatch); notifications + SSE + broadcast follow in later slices
We found that @strav/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.

Company News
Socket is joining the OpenJS Security Stewardship Program to fund Node.js vulnerability research, maintainer remediation, and security releases.

Security News
Two compromised GitHub Actions were re-enabled with malicious tags intact, exposing thousands of downstream repositories to Mini Shai-Hulud.

Research
/Security News
A malicious Firefox extension fetches its payload after installation to evade detection, steal Google session cookies, and automate account takeover.