If your website is deployed on Vercel but your domain DNS and email still live at SiteGround, Hostinger, or another shared host, this issue is common:
You click Webmail Login in the hosting dashboard and land on:
https://yourdomain.com/webmail/mail?token=...
Then your Next.js app returns 404.
This happened in production, and the fix below works reliably with App Router and Vercel deployments.
The Real Objective
The target setup was:
- Website hosting on Vercel
- Email hosting at SiteGround (or similar)
/webmailand/webmail/*always redirecting to the provider webmail endpoint- Tokenized URLs preserved so dashboard auto-login flows keep working
If you only redirect /webmail and ignore deeper paths like /webmail/mail?token=..., you still break real users.
Why the 404 Happens
When your domain points to Vercel via A/CNAME, Vercel is the web server for all paths on that domain.
That means these requests are now handled by your Next.js app too:
/webmail/webmail/mail/webmail/mail?token=...
If App Router has no matching route for those paths, 404 is correct behavior.
If you're rebuilding legacy stacks, this pattern appears often during WordPress to Next.js migrations.
Why the First Fixes Usually Fail
next.config redirect only for /webmail
This is the first thing most people try. It handles one path, but tokenized links often use deeper paths generated by your hosting panel.
Middleware for everything
Middleware can work, but for this exact use case it is more moving parts than you need. An App Router-native route handler is usually cleaner.
Forgetting query-string preservation
If the redirect drops ?token=..., the user gets bounced to a login screen instead of auto-login.
Production Fix: App Router Route Handlers + Catch-All
Create this structure:
app/
webmail/
route.ts
[...slug]/
route.ts
Step 1: Handle /webmail
// app/webmail/route.ts
import { NextResponse } from "next/server";
export const runtime = "edge";
const WEBMAIL_BASE = "https://your-webmail-host.example/webmail";
export function GET() {
return NextResponse.redirect(`${WEBMAIL_BASE}/`, 307);
}
Step 2: Handle /webmail/* and preserve query params
// app/webmail/[...slug]/route.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
export const runtime = "edge";
const WEBMAIL_BASE = "https://your-webmail-host.example/webmail";
export function GET(
request: NextRequest,
{ params }: { params: { slug: string[] } }
) {
const tail = `/${params.slug.join("/")}`;
const query = request.nextUrl.search;
return NextResponse.redirect(`${WEBMAIL_BASE}${tail}${query}`, 307);
}
Why This Works
app/webmail/route.tscatches the root pathapp/webmail/[...slug]/route.tscatches every nested path- query strings are forwarded unchanged
- deployment stays fully compatible with Vercel edge runtime
So both work:
https://yourdomain.com/webmail/
https://yourdomain.com/webmail/mail?token=...
Quick Deployment Checklist
- You are on App Router (
/appdirectory) - Both route files exist exactly at the paths above
- Your
WEBMAIL_BASEpoints to your provider's real webmail host - You redeployed Vercel after adding handlers
- You tested from the hosting dashboard login button, not only manual URL entry
Security and Operations Notes
- Do not log token query strings in server logs.
- Keep email infrastructure (MX, SPF, DKIM, DMARC) at your email provider.
- This fix is routing-only; it does not change mail delivery.
Internal Linking Opportunities That Converted Well
In production content, we used this article as a bridge to:
- architecture service pages like Next.js migration services
- implementation support pages like Custom web development
- short-form runbooks in Tutorials
If you want implementation review before launch, start here: Book a strategy call.
FAQ
Does this change MX records or mailbox data?
No. It only changes HTTP routing for /webmail/* paths.
Should I use 307 or 308?
Use 307 for temporary-preserve-method behavior during this kind of operational routing. Keep it explicit and test your provider flow.
Can this work for Hostinger, cPanel, or custom mail hosts?
Yes. Replace WEBMAIL_BASE with your provider endpoint and keep the catch-all route in place.