洪 民憙 (Hong Minhee)'s avatar
洪 民憙 (Hong Minhee)

@hongminhee@hollo.social · Reply to 洪 民憙 (Hong Minhee)'s post

Upyo 0.3.0をリリースしました。複数のメールプロバイダー間で自動フェイルオーバーができるプールトランスポートと、ResendとPlunkのサポートを追加。メール配信の信頼性が大幅に向上します。

洪 民憙 (Hong Minhee)'s avatar
洪 民憙 (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.