
洪 民憙 (Hong Minhee)
@hongminhee@hollo.social · Reply to 洪 民憙 (Hong Minhee)'s post
Upyo 0.3.0をリリースしました。複数のメールプロバイダー間で自動フェイルオーバーができるプールトランスポートと、ResendとPlunkのサポートを追加。メール配信の信頼性が大幅に向上します。

洪 民憙 (Hong Minhee)
@hongminhee@hackers.pub
Upyo 0.3.0 introduces three new transports that expand the library's email delivery capabilities. This release focuses on improving reliability through multi-provider support and offering more deployment options to suit different organizational needs.
Pool transport for multi-provider resilience
The new @upyo/pool package introduces a pool transport that combines multiple email providers into a single transport. This allows applications to distribute email traffic across different providers and automatically fail over when one provider experiences issues.
The pool transport supports several routing strategies. Round-robin distribution cycles through providers evenly, while weighted distribution allows you to send more traffic through preferred providers. Priority-based routing always attempts the highest priority transport first, falling back to others only when needed. For more complex scenarios, you can implement custom routing based on message content, recipient domains, or any other criteria.
import { PoolTransport } from "@upyo/pool";
import { SmtpTransport } from "@upyo/smtp";
import { MailgunTransport } from "@upyo/mailgun";
const pool = new PoolTransport({
strategy: "priority",
transports: [
{ transport: primaryProvider, priority: 100 },
{ transport: backupProvider, priority: 50 },
{ transport: emergencyProvider, priority: 10 },
],
maxRetries: 3,
});
const receipt = await pool.send(message);
This transport proves particularly valuable for high-availability systems that
cannot tolerate email delivery failures. It also enables cost optimization by
routing bulk emails to more economical providers while sending transactional
emails through premium services. Organizations migrating between email providers
can use weighted distribution to gradually shift traffic from one provider to
another. The pool transport handles resource cleanup properly through
AsyncDisposable
support and provides comprehensive error reporting that
aggregates failures from all attempted providers.
For detailed configuration options and usage patterns, refer to the pool transport documentation.
Installation
npm add @upyo/pool
pnpm add @upyo/pool
yarn add @upyo/pool
deno add jsr:@upyo/pool
bun add @upyo/pool
Resend transport
The @upyo/resend package adds support for Resend, a modern email service provider designed with developer experience in mind. Resend focuses on simplicity without sacrificing the features needed for production applications.
One of Resend's strengths is its intelligent batch optimization. When sending multiple emails, the transport automatically determines the most efficient sending method based on message characteristics. Messages without attachments are sent using Resend's batch API for optimal performance, while the transport seamlessly falls back to individual requests when needed. This optimization happens transparently, requiring no additional configuration.
import { ResendTransport } from "@upyo/resend";
const transport = new ResendTransport({
apiKey: "re_1234567890abcdef_1234567890abcdef1234567890",
});
const receipt = await transport.send(message);
Resend also provides built-in idempotency to prevent duplicate sends during network issues or application retries. The transport automatically generates idempotency keys, though you can provide custom ones when needed. Combined with comprehensive retry logic using exponential backoff, this ensures reliable delivery even during temporary service interruptions. Message tagging support helps organize emails and track performance across different types of communications through Resend's analytics dashboard.
The Resend transport guide provides comprehensive documentation on configuration and advanced features.
Installation
npm add @upyo/resend
pnpm add @upyo/resend
yarn add @upyo/resend
deno add jsr:@upyo/resend
bun add @upyo/resend
Plunk transport
The @upyo/plunk package brings support for Plunk, an email service that offers both cloud-hosted and self-hosted deployment options. This flexibility makes Plunk an interesting choice for organizations with specific infrastructure requirements.
For many teams, the ability to self-host email infrastructure is crucial for
compliance or data sovereignty reasons. Plunk's self-hosted option runs as
a Docker container using the driaug/plunk
image, giving you complete control
over your email infrastructure while maintaining a simple, modern API. The same
codebase works seamlessly with both cloud and self-hosted instances, requiring
only a different base URL configuration.
import { PlunkTransport } from "@upyo/plunk";
// Cloud-hosted
const cloudTransport = new PlunkTransport({
apiKey: "sk_1234567890abcdef1234567890abcdef1234567890abcdef",
});
// Self-hosted
const selfHostedTransport = new PlunkTransport({
apiKey: "your-self-hosted-api-key",
baseUrl: "https://mail.yourcompany.com/api",
});
The Plunk transport includes the production features you'd expect, such as
retry logic with exponential backoff, comprehensive error handling, and support
for attachments (up to 5 per message as per Plunk's API limits). Message
organization through tags helps track different types of emails, while priority
levels ensure urgent messages receive appropriate handling. The transport also
supports request cancellation through AbortSignal
, allowing your application
to gracefully handle timeouts and user-initiated cancellations.
Complete documentation and deployment guidance is available in the Plunk transport documentation.
Installation
npm add @upyo/plunk
pnpm add @upyo/plunk
yarn add @upyo/plunk
deno add jsr:@upyo/plunk
bun add @upyo/plunk
Migration guide
All new transports maintain Upyo's consistent API design, making them drop-in replacements for existing transports. The same message creation and sending code works with any transport:
import { createMessage } from "@upyo/core";
const message = createMessage({
from: "sender@example.com",
to: "recipient@example.com",
subject: "Hello from Upyo!",
content: { text: "Works with any transport!" },
});
const receipt = await transport.send(message);
What's next
We continue to work on expanding Upyo's transport options while maintaining the library's focus on simplicity, type safety, and cross-runtime compatibility. Your feedback and contributions help shape the project's direction.
For the complete changelog and technical details, see CHANGES.md.
For questions or issues, please visit our GitHub repository.