惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

J
Java Code Geeks
Martin Fowler
Martin Fowler
MongoDB | Blog
MongoDB | Blog
博客园 - Franky
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Microsoft Security Blog
Microsoft Security Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
博客园_首页
腾讯CDC
D
Docker
The Cloudflare Blog
量子位
爱范儿
爱范儿
L
LangChain Blog
博客园 - 三生石上(FineUI控件)
博客园 - 司徒正美
aimingoo的专栏
aimingoo的专栏
Blog — PlanetScale
Blog — PlanetScale
Jina AI
Jina AI
Apple Machine Learning Research
Apple Machine Learning Research
Hugging Face - Blog
Hugging Face - Blog
博客园 - 聂微东
Vercel News
Vercel News
MyScale Blog
MyScale Blog

Hacker News: Show HN

PurrrrrFocus: Pomodoro Timer App - App Store Workflow Engine — Multi-Step Orchestration for Bun RapidPhoto: Pro Photo Editor App - App Store GitHub - DheerG/swarms: Achieve extraordinary results with claude code across a variety of tasks SPICE simulation → oscilloscope → verification with Claude Code — Lucas Gerads Show HN: VCoding – A 5 MB native Windows IDE with no dynamic dependencies Show HN: LLMs don't hallucinate because they're bad at math, it's the format GitHub - Agent-FM/agentfm-core: AgentFM is a peer-to-peer network that turns everyday computers into a decentralized AI supercomputer. AgentFM lets you run massive AI workloads directly across a global mesh of idle CPUs and GPUs. Show HN: Tracking Top US Science Olympiad Alumni over Last 25 Years GitHub - Potarix/agent-hub: One place to talk to all your agents Show HN: Runtime security for AI agents(injection,tool abuse, data exfiltration) GitHub - dubeyKartikay/lazyspotify: Terminal Spotify client for macOS and Linux GitHub - the-banana-tool/king-louie: Easy to use GUI Personal AI Assistant. Win/Linux/Mac. Show HN I made my vacation rental bookable by AI agents–no Airbnb, 0% commission GitHub - basteez/jsf-autoreload: maven plugin to enable hot reload on jsf projects uvm32/hosts/host-gdbstub at main · ringtailsoftware/uvm32 GitHub - labsai/EDDI: Config-driven engine that turns JSON into production-grade AI agents. Multi-agent orchestration, 12+ LLM providers, MCP/A2A protocols, RAG, persistent memory, and enterprise compliance (EU AI Act, GDPR, HIPAA). Built on Quarkus. GitHub - glitchnsec/fortyone-oss: AI Executive Assistant Platform Quickstart | Alien GitHub - muxshed/shed: One stream in, or many. Every destination, simultaneously. No cloud middleman, no per-channel fees, no limits. GitHub - ocrbase-hq/ocrbase: 📄 PDF/IMG ->.MD/JSON Document OCR API for PaddleOCR and GLMOCR. Self-hostable. GitHub - impactjo/home-memory: MCP server that lets your AI assistant remember everything about your home. GitHub - Sets88/dbcls: DbCls is a powerful terminal database client that supports various databases GitHub - neptun2000/heor-agent-mcp GitHub - SeanFDZ/macmind: Single-layer transformer in HyperTalk for the classic Macintosh RollQuation: Math Puzzles - Apps on Google Play GitHub - dropbox/witchcraft Show HN: Agent-cache – Multi-tier LLM/tool/session caching for Valkey and Redis GitHub - opentalon/opentalon: OpenTalon is an open-source platform built from the ground up in Go as a robust alternative to OpenClaw LinkedIn™ 职位抓取工具 - Chrome 应用商店
GitHub - overflowy/imap2gmail: A self-contained mass-migr...
overflowy · 2026-06-27 · via Hacker News: Show HN

A self-contained mass-migrations orchestrator for Gmail.

app

Run one binary, open the browser, add dozens of source mailboxes, authorize each destination Gmail once, and sync them in parallel with live per-account logs.

Why

TL;DR: As a Google Admin, I got frustrated with the Google Import Tool. It sucks. It's slow, completely opaque, and doesn't even work properly.

Features

┌──────────────┐     ┌─────────────────────┐     ┌───────────────────┐
│  origin IMAP │ ──▶ │  imap2gmail (local) │ ──▶ │  Gmail (per-user) │
│  (host:port) │     │  + imapsync workers │     │  via OAuth token  │
└──────────────┘     └─────────────────────┘     └───────────────────┘
                            │
                     ┌──────┴──────┐
                     │  browser UI │  jobs orchestration
                     └─────────────┘
  • Bulk import - paste CSV (source_user,password,gmail) to add many accounts at once.
  • Per-account Gmail OAuth - authorize each destination once; access tokens are refreshed automatically sync.
  • Bounded parallelism - a worker pool (1–8 concurrent syncs) processes checked accounts.
  • Live logs - combined imapsync stdout/stderr streamed per operation via SSE, with status indicators (running/stopped).
  • Clean Stop - Stop / Ctrl-C kills the whole process group (imapsync + forked helpers), persists stopped status.
  • Dry Run - --dry is on until you explicitly turn it off.

Requirements

  • imapsync on PATH (the app preflights this on startup). Install e.g. with brew install imapsync.
  • A Google OAuth client (web app type) - you need its Client ID and Secret, and you must add the redirect URI (see Configuration) to the authorized redirect URIs in Google Cloud Console.

Build

# Build the self-contained binary (generates sqlc, builds frontend, embeds it)
task build

This produces imap2gmail. The frontend is compiled via Vite and embedded into the Go binary via //go:embed.

Run

Make sure you're running imap2gmail in a secure environment. Treat the environment as you would treat .env.prod files.

The server binds 127.0.0.1:<bind_port> (default 8080) and opens a browser to it. All state lives under the current working directory:

Path Contents Perms
data/db/data.db SQLite - settings, accounts, destinations, OAuth tokens 0600
data/logs/<source_user>/<timestamp>.log per-operation sync logs 0600
run/token-<id>.txt transient Gmail access-token files passed to imapsync 0600

Configuration

Open the Settings panel in the UI (its collapse state is remembered across reloads):

Setting Default Notes
OAuth Client ID / Secret (empty) Google OAuth Desktop credentials
Origin Host / Port / SSL "" / 993 / on Your source IMAP server
Bind Port 8080 Loopback listen port
imapsync flags see below Global behavior flags (validated)
Max Concurrent 1 Worker pool, clamped 1–8
Dry Run on Adds --dry until you turn it off

Redirect URL

The redirect URL is derived, not stored: http://127.0.0.1:<bind_port>/. Add it to Authorized redirect URIs in your Google OAuth client. Changing bind_port requires re-registering the URI and restarting the app (the server only rebinds on restart).

How Gmail auth works

  1. Click Auth on an account → the app opens Google's consent URL (requesting offline access + a refresh token).
  2. Google redirects to http://127.0.0.1:<bind_port>/?code=…&state=<nonce>.
  3. The app exchanges the code, stores the refresh token, and marks the destination authenticated.
  4. During sync, access tokens are minted from the refresh token and refreshed every 5 minutes. A manual Exchange Code fallback is available if the redirect flow can't complete.

Using it

  1. Configure the origin IMAP host/port/SSL and your Google OAuth credentials, then Save.
  2. Authorize each destination Gmail (Auth button per account).
  3. Check the accounts you want to migrate (Select All / Select None, or per-row).
  4. Sync All (or Sync per row). The log pane auto-switches to the first syncing account and shows live output.
  5. Watch the status badges: Running (pulsing), OK, Failed, Skipped, Stopped, Idle.
  6. Stop at any time - running accounts are killed and marked stopped.

Dry Run is on by default. Turn it off in Settings to perform a real migration.

How sync works

The runner is a single global orchestrator (one sync run at a time):

  1. Queue - checked accounts (skipping duplicates and unauthenticated destinations) enter a worker pool bounded by max_concurrent.
  2. Per account - mint a Gmail access token → write a 0600 token file → build the imapsync argv → spawn imapsync in its own process group.
  3. imapsync argv - the app owns connection/auth flags: source (--host1/--port1/--ssl1/--user1/--password1), destination hardwired to Gmail (--host2 imap.gmail.com --port2 993 --ssl2 --user2 <gmail> --oauthaccesstoken2 <tokenfile> --gmail2 --nolog), plus your global behavior flags, plus --dry if Dry Run is on.
  4. Stream - combined stdout/stderr is written to the operation log file and pushed to the browser over SSE.
  5. Status - each account ends as ok, failed, skipped, or stopped.

Flag safety

The global imapsync flag string is tokenized with shlex (never a shell) and validated against a denylist of app-managed flags. You cannot override connection, credentials, identity, OAuth, --dry, or logging flags (--log/--nolog/--logfile/--logdir) - those are owned by the app.

Stop & shutdown

  • Stop button cancels the run and sends SIGKILL to each child's whole process group (so forked perl/imapsync helpers die and pipes close). In-flight accounts are marked stopped; not-yet-started ones stay idle.
  • Ctrl-C / SIGTERM triggers graceful shutdown: stop the runner, wait up to 15s for finalization, then shut down the HTTP server (5s).
  • Startup recovery clears any stale running status left by a crash.

Tech stack

  • Backend: Go 1.26.
  • Frontend: React 19, Mantine 9, TanStack React Query 5, TypeScript, Vite 8 - embedded into the binary at build time.
  • Engine: imapsync invoked as a subprocess.

Third-party software

This project invokes imapsync as an external program. imapsync is not part of this project’s license. See the imapsync project for its own license terms.

License

This project is licensed under the PolyForm Noncommercial License 1.0.0.

You may use, copy, modify, and distribute this software for noncommercial purposes only.

Commercial use is not permitted without separate written permission. This includes selling, reselling, sublicensing, hosting as a paid service, or including this software in a paid product or paid service.

For commercial licensing, contact: overflowy@riseup.net