October 20, 2026 · 5 min read
We moved two real mailboxes off Yandex 360 — here's what actually broke
A field note from migrating support@ and info@ off Yandex 360 to our own mailbox server: the throttling that stalls every big import, the cutover order that matters, and a bug we caused ourselves.
We run a transactional email platform, and one of our own domains — a two-person studio site — still had its mail on Yandex 360. Two mailboxes: a support address and an info address. A few hundred messages between them. This is the story of moving them onto our own mailbox server, because the migration path our dashboard offers is the one we just walked, including the parts that went wrong.
If you're planning the same move, the useful bits are here: why imports stall at about the same place every time, why the order of operations matters more than the tool, and one bug that was entirely our fault.
The plan was simple, and mostly right
The shape of a mail migration is always the same: get the old mail across while the old provider still answers, then flip where new mail goes, then let the old provider go quiet. In our case:
- Create the mailboxes on the destination — our own mailbox server, same addresses.
- Start an import that pulls the history over IMAP, using an app password rather than the account's real one.
- Leave the MX records alone. New mail keeps arriving at Yandex.
- When the import catches up, flip MX to the new host.
- Run the import one more time. It's incremental — it only pulls what arrived since the last pass.
- Keep the old provider's DNS records (DKIM, SPF) in place until nothing sends from there anymore.
Step six is the one people skip. More on that below.
The imports stall, and it's not a bug
Both imports ran fine for the first few minutes and then stopped dead with the same error from Yandex:
84 NO [UNAVAILABLE] UID FETCH Completed.
That's a temporary failure code — the account is fine, the credentials are fine, listing folders still works. Yandex is telling you that you've pulled enough messages for now. It's a per-account rolling window, so waiting is the only cure; hammering it just extends the wait.
We transferred a couple of hundred messages per mailbox before hitting it, which for our sizes was most of the archive. The rest came across on later passes.
Our importer treats that error as a scheduling hint rather than a failure: the pass ends, the import goes back in the queue with a 30-minute delay, and it tries again — up to 16 times before it tells you to run it again later. Because IMAP imports are incremental and idempotent, every pass resumes where the last one stopped. Nothing is fetched twice, and nothing is skipped. You start the import once and walk away.
Two things make a real difference to how far each pass gets:
- Rate caps. We run imapsync with
--maxmessagespersecond 5and--maxbytespersecond 1000000. Slower passes get further before the provider objects. The instinct to remove the throttle and "just finish it" is exactly wrong. - Timing. If the old provider throttles you during business hours, it throttles you less at 3am. Our retry delay of 30 minutes isn't tuned to any provider's exact window — it just needs to be long enough to matter.
Then we broke it ourselves
Halfway through, one of the imports died with a message that had nothing to do with mail:
App\Jobs\RunMailImport has been attempted too many times.
That one was ours. We were shipping code to the platform while the import ran, and a deploy recreates the queue worker — which kills whatever job is running on it. The import job is deliberately single-try (a crash should surface as a failed import you can re-run, not a silent retry loop), so the killed pass was recorded as a failure. The mailbox was fine. The import was fine. The deploy just shot it in the back.
The fix is a small one: when a pass is interrupted by the worker going away — as opposed to the provider refusing to serve more — the job now puts itself back in the queue instead of giving up, as long as it still has attempts left. IMAP imports resume cleanly, so an interruption costs one pass, not the migration. If your provider is handling the import for you, ask them what happens to a running import during their deploys. Ours now survives them.
The order of operations is the real lesson
The part that made this painless: we never had a window where mail could be lost.
- The old provider stayed authoritative (MX unchanged) until the import was current.
- The final pass before the MX flip took seconds, because it only had to pull the day's new mail.
- After the flip, the old provider's DKIM key and SPF record stayed published for a week, because one of us was still sending from Yandex webmail. Mail sent from there still authenticated. When that stopped, the records came out.
If you flip MX first and import second, you're doing the same work under time pressure, with new mail landing in a mailbox that doesn't have the history yet. Don't do that to yourself.
The checklist, if you're doing this next weekend
- Create the destination mailboxes before you touch anything else.
- Start the import with an app password, not the account password. Revoke it afterwards.
- Expect throttling, keep the rate caps, and let the import retry on its own schedule.
- Don't migrate during a deploy window — on either side.
- Flip MX only when the import is current.
- Leave DKIM and SPF on the old provider until nothing sends from there.
- Send a real message in and out afterwards, and read the headers. Delivered is the only test that counts.
The whole thing took an afternoon of attention spread over two days, most of it waiting for a provider to like us again. If you're moving mail and want the long version — including the provider-specific app-password instructions — the migration guide walks through it.