Adds a second flow alongside the URL-to-EPUB pipeline: - New POST /send-file endpoint accepts multipart/form-data with a `file` and `readerEmail`, attaches the file to an email, and ships it to the reader as-is. No conversion — the device decides what it accepts (EPUB, PDF, MOBI, FB2, ...). - 25 MB cap enforced both client-side and server-side (multer). - Shares the same 20/hour rate limit as /send-article (now sendLimiter). - UI: dropzone with drag/drop + click-to-pick + visible filename feedback. - Shared e-reader email input across both flows. - Codeberg source link added to the footer. - Version bumped 0.1.0 → 0.2.0.
4.4 KiB
Send to E-Reader
Convert web articles to EPUB and email them straight to your e-reader. Works with any device that accepts emailed files — Kindle, PocketBook, or anything else with a similar service.
Built with Express 5 + TypeScript. Hosted at read.atanasov.fi.
How it works
Two ways to send something to your e-reader:
URL → EPUB
- You paste an article URL and your e-reader's email address.
- The server fetches the page, runs Mozilla Readability over it to strip ads/chrome, builds an EPUB, and emails it to the address you gave.
- The EPUB is deleted from the server immediately after sending.
Upload a file
- Drag (or pick) a file — EPUB, PDF, MOBI, anything your device accepts.
- The server attaches it to an email and sends it to your e-reader as-is, no conversion.
- The file is deleted from the server immediately after sending. Max size: 25 MB.
Supported devices
Any device that accepts files via email works — the app doesn't restrict by domain.
| Device | Email pattern |
|---|---|
| Amazon Kindle | *@kindle.com |
| PocketBook | *@pbsync.com |
| Anything else | whatever address your device gives you |
You'll need to add the sender address (the Gmail account this app sends from) to your device's approved-senders list — that's a one-time per-device setup.
Prerequisites
- Node.js 20 or newer
- An SMTP-capable email provider. Defaults are set up for Resend — sign up (no waitlist), verify your domain, grab an API key.
Local development
git clone <your-fork>
cd send_to_kindle
npm install
cp .env.example .env # then fill in SMTP_PASSWORD (Resend API key) and MAIL_FROM
npm run dev
Server listens on http://localhost:3000 (override with PORT).
Production build
npm run build
npm run start
Environment variables
| Variable | Required | Default | Notes |
|---|---|---|---|
SMTP_HOST |
no | smtp.resend.com |
Any SMTP server works |
SMTP_PORT |
no | 587 |
587 = STARTTLS (preferred — port 465 is blocked by most VPS providers) |
SMTP_USER |
yes | — | For Resend, literally the string resend |
SMTP_PASSWORD |
yes | — | For Resend, your API key (re_…) |
MAIL_FROM |
yes | — | Sender address, e.g. read@atanasov.fi. Must be from a verified domain on your provider. |
PORT |
no | 3000 |
Listen port |
Resend setup (quick)
- Sign up at resend.com.
- Add your domain (e.g.
atanasov.fi) and add the SPF/DKIM/return-path DNS records they generate. Verification usually completes in a few minutes. - Create an API key.
- In
.env:SMTP_USER=resend SMTP_PASSWORD=re_xxxxxxxxxxxxxxxxxx MAIL_FROM=send@read.atanasov.fi
For a different provider, just point SMTP_HOST / SMTP_PORT / SMTP_USER / SMTP_PASSWORD at it — any standard SMTP service works.
API
POST /send-article
Body (JSON):
{
"url": "https://example.com/article",
"readerEmail": "your-device@kindle.com"
}
Response on success:
{
"success": true,
"message": "Article sent to your e-reader",
"title": "Article Title"
}
POST /send-file
Body (multipart/form-data):
file— the binary file (max 25 MB)readerEmail— destination address
Response on success:
{
"success": true,
"message": "File sent to your e-reader",
"title": "original-filename.epub"
}
Rate limit
Both endpoints share a limit of 20 sends per IP per hour.
Limitations
- Articles must be publicly accessible — no paywalled or login-required pages.
- Server-side fetch means JS-heavy SPAs may extract poorly (the page must render meaningful HTML without JavaScript).
- Some sites block non-browser user-agents; the app sends a Chrome UA but can still be refused.
Stack
- Express 5 — HTTP server
- @mozilla/readability — article extraction
- jsdom — DOM for Readability
- @lesjoursfr/html-to-epub — EPUB generation
- nodemailer — SMTP client
- multer — multipart/form-data upload parsing
- express-rate-limit — per-IP rate limiting
License
GPL-3.0-only. See LICENSE.