bởi Lin X.

Postal is a fully featured, self-hosted mail server for websites and web servers. A free open-source alternative to Sendgrid, Mailgun, and Postmark.
Postal is a full-featured, open-source mail server written in Ruby on Rails that handles inbound and outbound email for web applications. It provides a self-hosted alternative to services like Sendgrid or Mailgun, exposing HTTP APIs for sending mail and webhooks for delivery events. The typical buyer is a backend engineer embedding transactional email infrastructure into their own infrastructure stack.
.github/ - CI workflow definitions and issue templates for the upstream projectapp/ - Core Rails application: controllers, models, mailers, services, senders, scheduled tasks, and assetsapp/assets/ - Compiled frontend assets: stylesheets, fonts, and icon SVGs for the web UIapp/controllers/ - Rails controllers handling the web UI and HTTP API endpointsapp/helpers/ - Rails view helper modulesapp/lib/ - Internal application-level libraries and modulesapp/mailers/ - ActionMailer classes for system-level emails (alerts, invitations, etc.)app/models/ - ActiveRecord models: Server, Domain, Message, Credential, IPPool, etc.app/scheduled_tasks/ - Background/cron job definitions for queue processing and cleanupapp/senders/ - Sender strategy classes (SMTP, SendGrid relay, etc.)app/services/ - Service objects encapsulating complex business logic (message processing, DNS checks)app/util/ - Utility classes and helpers used across the applicationconfig/ - Rails configuration: routes, initializers, database, environmentsdb/ - Database schema and migrationsdoc/ - Internal documentation and architecture notesdocker/ - Dockerfile and entrypoint scripts for containerised deploymentlib/ - Rails lib directory: rake tasks, custom middleware, extensionspublic/ - Static files served directly by the web serverscript/ - Developer utility scriptsdocker-compose.yml - Local development stack definition (MySQL, Redis, Postal)CHANGELOG.md - Release historyCONTRIBUTING.md - Contribution guidelinesREADME.md - Project overview and quickstart linksKhởi chạy sandbox cách ly và chạy phía máy chủ — không cần cài đặt cục bộ.
Tetrees AI Review cho phiên bản này
This Ruby library / package completed archive review with strong static results. Structure, dependency manifests, documentation, functional source, and common risk patterns were checked by the Tetrees verification pipeline; runtime phases are stated separately.
Deterministic AVCP artifact review
Quy trình avcp-2026-08-04.1 · SHA-256 6c9526f3b2708c91…
This version-scoped review deterministically inspects the submitted archive for structure, dependencies, documentation, functional source, and common malicious or high-risk signals. Build and test phases are reported as passed only after an isolated sandbox audition. It is not a guarantee of perfect security.
Đã đánh giá 4 thg 8, 2026
Đưa sản phẩm này thẳng vào AI IDE, trình tạo web hoặc cloud IDE của bạn.
Kết nối Tetrees với AI IDE tương thích để liệt kê sản phẩm bạn sở hữu và nhận ZIP đã xác minh mà không cấp quyền tải lên của người bán.
Chưa có đánh giá.
Sign in to join the discussion
Loading discussion…
SECURITY.md - Security disclosure policyThis is a Ruby on Rails application, not a Node.js package. There are no npm dependencies to install.
# No npm install required - this is a Ruby/Rails application.
# Runtime dependencies are managed via Bundler (Gemfile).
Native / non-Node build steps required before any integration:
# 1. Ruby >= 3.1 and Bundler
gem install bundler
bundle install
# 2. MySQL (or MariaDB) and Redis must be running
# Use the provided docker-compose for local development:
docker compose up -d
# 3. MariaDB schema setup
bundle exec rails db:create db:schema:load db:seed
# 4. Build assets
bundle exec rails assets:precompile
Clone or drop the source/ directory onto a host that has Ruby, MySQL/MariaDB, and Redis available.
Copy and edit the configuration file:
cp config/postal.example.yml config/postal.yml
# Edit config/postal.yml: set database credentials, Redis URL, SMTP bind address, signing keys
Set required environment variables (or populate config/postal.yml):
export POSTAL_DB_HOST=127.0.0.1
export POSTAL_DB_PORT=3306
export POSTAL_DB_NAME=postal
export POSTAL_DB_USERNAME=postal
export POSTAL_DB_PASSWORD=secret
export POSTAL_REDIS_URL=redis://127.0.0.1:6379/1
export POSTAL_WEB_HOST=postal.yourdomain.com
export POSTAL_SIGNING_KEY_PATH=/opt/postal/config/signing.key
Generate a signing key (run once):
openssl genrsa -out /opt/postal/config/signing.key 2048
Start all Postal processes:
bundle exec postal web-server # HTTP API + UI on port 5000
bundle exec postal smtp-server # SMTP listener
bundle exec postal worker # Background message processing
bundle exec postal cron # Scheduled tasks
To call Postal's HTTP Send API from a Node/TypeScript service, point your HTTP client at the running Postal instance (no native Node module needed).
Because Postal is a Rails application with no exported TypeScript/JavaScript symbols, the public surface is its HTTP API. The following are the real HTTP endpoints documented by the project and visible in the controllers directory.
interface PostalSendMessagePayload {
to: string[];
cc?: string[];
bcc?: string[];
from: string;
sender?: string;
subject: string;
plain_body?: string;
html_body?: string;
attachments?: Array<{ name: string; content_type: string; data: string }>; // base64 data
headers?: Record<string, string>;
reply_to?: string;
tag?: string;
bounce?: boolean;
}
interface PostalSendMessageResponse {
status: "success" | "error";
time: number;
flags: Record<string, unknown>;
data: {
message_id: string;
messages: Record<string, { id: number; token: string }>;
};
}
Send a single transactional message. Requires an X-Server-API-Key header set to a credential created in the Postal UI.
interface PostalSendRawPayload {
mail_from: string;
rcpt_to: string[];
data: string; // Raw RFC 2822 message, base64-encoded
bounce?: boolean;
}
Send a pre-composed RFC 2822 raw message. Use this when you already have a fully-formed MIME message (e.g., produced by Nodemailer's buildMessage()).
interface PostalGetMessageParams {
id: number;
_expansions?: boolean | string[];
}
interface PostalMessageDetail {
id: number;
token: string;
status: string;
details: Record<string, unknown>;
inspection: Record<string, unknown>;
plain_body: string;
html_body: string;
attachments: unknown[];
headers: Record<string, string>;
raw_message: string;
}
Retrieve full details and delivery status of a message by its numeric ID. Use after sending to audit delivery or fetch bounce details.
A backend service sends a password-reset email through a running Postal instance using the HTTP API.
import axios from "axios";
const POSTAL_URL = process.env.POSTAL_URL ?? "https://postal.yourdomain.com";
const POSTAL_API_KEY = process.env.POSTAL_API_KEY ?? "";
async function sendPasswordReset(toEmail: string, resetLink: string) {
const response = await axios.post(
`${POSTAL_URL}/api/v1/send/message`,
{
to: [toEmail],
from: "user@example.com",
subject: "Reset your password",
html_body: `<p>Click <a href="${resetLink}">here</a> to reset your password.</p>`,
plain_body: `Reset your password: ${resetLink}`,
tag: "password-reset",
},
{
headers: {
"X-Server-API-Key": POSTAL_API_KEY,
"Content-Type": "application/json",
},
}
);
const data = response.data as { status: string; data: { message_id: string } };
if (data.status !== "success") throw new Error("Postal send failed");
return data.data.message_id;
}
When you need full MIME control (inline images, S/MIME signing), build the raw message and submit it via /api/v1/send/raw.
import nodemailer from "nodemailer";
import axios from "axios";
const POSTAL_URL = process.env.POSTAL_URL!;
const POSTAL_API_KEY = process.env.POSTAL_API_KEY!;
async function sendRawMime(to: string) {
const transporter = nodemailer.createTransport({ jsonTransport: true });
const info = await transporter.sendMail({
from: "user@example.com",
to,
subject: "Invoice #1234",
text: "Please find your invoice attached.",
});
// nodemailer jsonTransport gives us the raw source
const rawBase64 = Buffer.from(
(info as unknown as { message: string }).message
).toString("base64");
const res = await axios.post(
`${POSTAL_URL}/api/v1/send/raw`,
{
mail_from: "user@example.com",
rcpt_to: [to],
data: rawBase64,
},
{ headers: { "X-Server-API-Key": POSTAL_API_KEY } }
);
return res.data;
}
After sending, retrieve message status to confirm delivery or detect bounces.
import axios from "axios";
async function getMessageStatus(messageId: number): Promise<string> {
const POSTAL_URL = process.env.POSTAL_URL!;
const POSTAL_API_KEY = process.env.POSTAL_API_KEY!;
const res = await axios.get(`${POSTAL_URL}/api/v1/messages/message`, {
params: { id: messageId, _expansions: true },
headers: { "X-Server-API-Key": POSTAL_API_KEY },
});
const detail = res.data.data as { status: string };
return detail.status; // "Sent", "Bounced", "HeldAsSpam", etc.
}
.github/ - GitHub Actions CI pipeline (ci.yml) and issue template configuration.app/assets/ - Sprockets-managed fonts, icons (SVG), stylesheets, and the asset manifest.app/controllers/ - Rails controllers for both the browser UI and the versioned HTTP API (/api/v1/).app/helpers/ - View helpers used in ERB templates.app/lib/ - Application-scoped Ruby modules (not gem-level), such as message parsers.app/mailers/ - ActionMailer classes for outbound system notifications (alerts, user invites).app/models/ - ActiveRecord models covering every core domain concept: Server, Domain, Message, Credential, IPPool, Webhook, etc.app/scheduled_tasks/ - Cron-triggered tasks (queue expiry, bounce processing, log cleanup).app/senders/ - Strategy pattern implementations for delivering mail (direct SMTP, relay, SpamAssassin integration).app/services/ - Service objects for DNS validation, message queuing, suppression list handling.app/util/ - Standalone utility classes (IP range parsing, token generation).config/ - routes.rb, database.yml, environment configs, and initializers.db/ - schema.rb (authoritative DB structure) and numbered migrations.doc/ - Architecture diagrams and internal decision records.docker/ - Dockerfile and docker-entrypoint for the official container image.lib/ - Rake tasks, Rack middleware, and Ruby extensions loaded outside app/.public/ - Static HTML error pages and compiled asset output directory.script/ - One-off developer scripts (data migrations, diagnostic helpers).docker-compose.yml - Spins up MySQL, Redis, and Postal together for local development.POSTAL_SIGNING_KEY_PATH points to a non-existent file. Fix: run openssl genrsa -out <path> 2048 before first start.utf8mb4 charset and utf8mb4_unicode_ci collation or migrations fail. Fix: add character-set-server=utf8mb4 to my.cnf.401.postal.yml.GET /api/v1/public_key and verify the X-Postal-Signature header using RSA-SHA1 before trusting payload content.RAILS_ENV=production bundle exec rails assets:precompile before starting the web server.I have the source code for the Postal open-source mail server (a Ruby on Rails application)
located in the `source/` directory of my project. I also have `USAGE.md` which documents
the HTTP API surface and setup steps.
My project is a Node.js/TypeScript backend (Express). I need you to:
1. Read `USAGE.md` and `source/` to understand all available HTTP API endpoints
(especially /api/v1/send/message, /api/v1/send/raw, /api/v1/messages/message).
2. Create a typed TypeScript client module at `src/lib/postalClient.ts` that wraps
these endpoints with full request/response types.
3. Add environment variable handling for POSTAL_URL and POSTAL_API_KEY with
validation on startup.
4. Wire the client into my existing Express app so I can call `postalClient.sendMessage(...)`
from any route handler.
5. Add a webhook receiver route that verifies the X-Postal-Signature header using
the public key from /api/v1/public_key.
6. Show me how to run Postal locally using the docker-compose.yml in source/ alongside
my Express app.
Work step by step and confirm each step before proceeding to the next.
Postal is released under the MIT License (see source/LICENSE if present, or the upstream repository). The upstream project is maintained by the Postal Server team and community contributors.
Upstream repository: https://github.com/postalserver/postal Documentation: https://docs.postalserver.io
This product’s unique contribution is clean room implementation of valuable code block into AVCP compatible standard.
Hướng dẫn cài đặt đầy đủ và prompt tích hợp sẽ mở khóa sau khi mua.
CMS, Storefront & Platform Add-ons
Miễn phí