Building a Secure Email Migration Tool: OAuth, Encryption, and Privacy by Design

Published: (February 9, 2026 at 06:08 AM EST)
4 min read
Source: Dev.to

Source: Dev.to

When building tools that handle user credentials and email data, security isn’t optional—​it’s fundamental. Below are the key architectural decisions that made a POP3‑to‑Gmail migration service trustworthy.

OAuth for Gmail Access

Decision: Use Google OAuth instead of asking for the user’s Gmail password.

Benefits

  • The service never sees the user’s Google password.
  • Users authenticate directly with Google.
  • Minimal permission scope (gmail.insert only).
  • Automatic token refresh.
  • Users can revoke access anytime via Google Account settings.
// Request minimal scope
const SCOPES = ['https://www.googleapis.com/auth/gmail.insert'];

// Users authenticate with Google, receive OAuth code
// Exchange code for tokens server‑side
// Store refresh token encrypted
// Use for automated background sync

Key insight: gmail.insert allows adding messages but cannot read, modify, or delete existing email—​the principle of least privilege in action.

Encrypting POP3 Credentials

Challenge: Background sync needs POP3 passwords, but plaintext passwords must never hit the server.

Solution: Encrypt passwords in the browser before transmission.

Architecture

  1. Generate a one‑time public/private key pair server‑side.
  2. Publish the public key at /pop3-migrator.pub.asc.
  3. The client fetches the public key, encrypts the POP3 password locally, and sends the ciphertext to the server.
  4. The server decrypts only when it needs to open a POP3 connection.

Why it matters

  • Network sniffing can’t reveal passwords (they’re already encrypted).
  • A database breach won’t expose plaintext passwords.
  • Exposure window is minimized.

Privacy by Deletion

Challenge: Storing email metadata creates privacy risks and compliance burdens.

Solution: Delete messages from the POP3 server after a successful sync to Gmail.

Benefits

  • No need to store what emails users have.
  • No message metadata in the database.
  • Reduces GDPR/privacy compliance surface area.
  • Users’ email lives only in Gmail (single source of truth).

Trade‑off: Users must accept that messages cannot be re‑synced.

Implementation note: Deleting from the source also prevents duplicate imports if other migration tools are used in parallel.

Failure Notifications

Challenge: Silent failures lead to terrible UX and leave users uncertain about migration status.

Solution: Send email notifications when messages fail to import.

Typical failure scenarios

  • Oversized messages (> 10 MB)
  • Malformed messages
  • Network failures
  • API quota exceeded

Data Storage Policy

Principle: Only store what’s necessary for the service to function.

What we storeWhat we don’t store
OAuth refresh tokens (encrypted)Email content
POP3 credentials (encrypted)Email metadata (subjects, senders, dates)
Sync state (which messages already synced)User’s email list
Configuration (server, port, username)Read/unread status

Implementation: Use POP3 message UIDs (unique identifiers) to track synced messages without storing the actual message data.

SSRF Prevention

Challenge: Users provide hostnames; malicious actors could target internal services.

Solution: Validate and block private IP ranges.

Blocked ranges

  • 127.0.0.1, ::1 (localhost)
  • 10.0.0.0/8
  • 172.16.0.0/12
  • 192.168.0.0/16
  • Link‑local addresses
  • DNS rebinding attempts

Why it matters: Prevents attackers from using the service to probe internal networks or attack localhost services.

Security Decisions Summary

DecisionRationale
Stateful service with encrypted state storageNeeded for continuous sync; stateless would lose progress.
Client‑side encryption for POP3 credentialsPassword never travels in plaintext.
OAuth over password storageHigher user trust; direct Google authentication.
Encrypt early, decrypt lateMinimizes the window where sensitive data is accessible.
Privacy by deletionNot storing data is safer than securing stored data.
Fail loudly in development, notify users in productionImproves UX and debugging.
Minimal scope creepRequest only the permissions actually needed.

Pre‑Launch Checklist

  • OAuth flow works end‑to‑end.
  • Credentials are encrypted before leaving the browser (verify in the network tab).
  • SSRF prevention blocks private IPs.
  • Oversized messages are handled gracefully.
  • Email notifications are sent on failures.
  • Users can revoke access via Google Account settings.

Conclusion

Building secure migration tools requires careful thinking about:

  • Authentication: Prefer OAuth over password storage.
  • Encryption: Perform client‑side encryption before transmission.
  • Privacy: Delete data you don’t need.
  • Transparency: Notify users of failures.
  • Least privilege: Request only the permissions you actually need.

The result is a tool users can trust with their email history. If you’re building similar tools, I hope these patterns help. What security considerations have you faced in your projects?

0 views
Back to Blog

Related posts

Read more »