Getting Started
Install fumi and send your first SMTP session.
Install
bun add @puiusabin/fumiCreate a server
import { Fumi } from "@puiusabin/fumi";
const app = new Fumi({ authOptional: true });
app.onData(async (ctx, next) => {
const chunks: Uint8Array[] = [];
for await (const chunk of ctx.stream) {
chunks.push(chunk);
}
const raw = Buffer.concat(chunks).toString();
console.log(raw);
await next();
});
await app.listen(2525);
console.log("SMTP server listening on port 2525");Test it
Send a message with netcat:
printf "EHLO test\r\nMAIL FROM:<sender@example.com>\r\nRCPT TO:<you@example.com>\r\nDATA\r\nSubject: test\r\n\r\nHello\r\n.\r\nQUIT\r\n" | nc localhost 2525Next steps
Rejecting connections
ctx.reject() throws an SMTPError internally and has return type never. The TypeScript compiler treats any code after it as unreachable.
app.onMailFrom(async (ctx, next) => {
if (ctx.address.address.endsWith("@blocked.example")) {
ctx.reject("Domain blocked", 550);
// unreachable — compiler knows this
}
await next();
});Closing the server
app.listen() returns a Promise<void>. app.close() does too.
const app = new Fumi({ authOptional: true });
await app.listen(2525);
// later
await app.close();