When using recursive routing for dual-WAN failover, RouterOS handles the actual switchover automatically — but it does it silently. Without some form of monitoring layered on top, you won’t know a failover has happened until someone complains the internet feels slow, or you happen to log in and notice the wrong route is active. This guide covers a scheduler-based approach that watches the state of each WAN route and sends you an email the moment something changes.
How recursive routing exposes link state
In a recursive routing setup, each default route resolves its next-hop by looking up a host route that has check-gateway=ping set. When the gateway ping fails, RouterOS marks that host route as inactive, which in turn makes the default route that depends on it inactive. The higher-priority route drops out of the active routing table and the next best route takes over — all automatically.
This is what we exploit for monitoring. Instead of trying to detect the link failure itself, we simply watch whether the default route with comment=primary_route (or secondary_route) is currently active. If it’s active, the link is up and traffic is flowing through it. If it’s inactive, the link is down and RouterOS has already moved traffic elsewhere. The route’s inactive state becomes a reliable, real-time signal we can poll on a schedule.
The flip-flop scheduler pattern
The naive approach to monitoring would be to run a single scheduler every 30 seconds that checks the route state and sends an email if anything has changed. The problem is that once a link goes down you’d get an alert email every 30 seconds until it comes back — inbox flooded, alerts ignored.
This setup uses a flip-flop pattern instead. For each WAN link, two schedulers are defined — one active, one disabled. They swap roles the moment a state change is detected:
- The active-check scheduler runs on a regular interval while the link is up. The moment it detects the route has gone inactive, it sends one alert email, disables itself, and enables the inactive-check scheduler.
- The inactive-check scheduler then takes over, running on a regular interval while the link is down. The moment it detects the route has come back active, it sends one recovery email, disables itself, and re-enables the active-check scheduler.
The result is exactly one email per event — one when the link goes down, one when it comes back up — no matter how long the outage lasts.
Email tool configuration
Before creating the schedulers, configure the RouterOS email tool. This only needs to be done once and applies to all scripts that use /tool e-mail send.
/tool e-mail
set from=test@mikrotikmasters.com \
password=helloworld123 \
port=587 \
server=mail.mikrotikmasters.com \
user=test-mikrotik
| Setting | Value |
|---|---|
| Server | mail.mikrotikmasters.com |
| Port | 587 (STARTTLS) |
| Username | test-mikrotik |
| From address | test@mikrotikmasters.com |
Port 587 uses STARTTLS — RouterOS will upgrade the connection to TLS automatically after the initial handshake. No additional TLS configuration is required.
WAN1 — primary link
primary_active_check — starts enabled, runs while the primary link is up.
:local routeID [/ip route find where comment="primary_route"]
:local status [/ip route get $routeID inactive]
:if ($status = true) do={
:log info "Primary WAN is INACTIVE"
/system/scheduler/disable primary_active_check
/system/scheduler/enable primary_inactive_check
:local rname [/system identity get name]
:local rdate [/system clock get date]
:local rtime [/system clock get time]
/tool e-mail send to="alerts@mikrotikmasters.com" \
subject="WAN Alert: Primary Link Down - $rname" \
body="Router Name: $rname \nDate: $rdate \nTime: $rtime \nStatus: Primary Link Down"
}
Every interval this scheduler checks whether the primary-isp route is active. As long as the primary link is up and the route is active, the if condition evaluates false and nothing happens — no log entry, no email. The moment the route goes inactive (primary gateway ping fails), the condition fires and three things happen simultaneously: one alert email is sent, this scheduler disables itself, and primary_inactive_check is enabled to take over watching.
primary_inactive_check — starts disabled, runs while the primary link is down.
:local routeID [/ip route find where comment="primary_route"]
:local status [/ip route get $routeID inactive]
:if ($status != true) do={
:log info "Primary WAN is ACTIVE"
/system/scheduler/enable primary_active_check
/system/scheduler/disable primary_inactive_check
:local rname [/system identity get name]
:local rdate [/system clock get date]
:local rtime [/system clock get time]
/tool e-mail send to="alerts@mikrotikmasters.com" \
subject="WAN Recovery: Primary Link Up - $rname" \
body="Router Name: $rname \nDate: $rdate \nTime: $rtime \nStatus: Primary Link Up"
}
This scheduler sits dormant until its counterpart enables it. Once running, it polls the same route on the same interval but looks for the opposite condition — it’s waiting for the route to become active again. When the primary link recovers and the gateway ping succeeds, this scheduler fires a recovery email, re-enables primary_active_check, and disables itself. The system is back to its normal monitoring state.
WAN2 — secondary link
secondary_active_check — starts enabled, runs while the secondary link is up.
:local routeID [/ip route find where comment="secondary_route"]
:local status [/ip route get $routeID inactive]
:if ($status = true) do={
:log info "Secondary WAN is INACTIVE"
/system/scheduler/disable secondary_active_check
/system/scheduler/enable secondary_inactive_check
:local rname [/system identity get name]
:local rdate [/system clock get date]
:local rtime [/system clock get time]
/tool e-mail send to="alerts@mikrotikmasters.com" \
subject="WAN Alert: Secondary Link Down - $rname" \
body="Router Name: $rname \nDate: $rdate \nTime: $rtime \nStatus: Secondary Link Down"
}
secondary_inactive_check — starts disabled, runs while the secondary link is down.
:local routeID [/ip route find where comment="secondary_route"]
:local status [/ip route get $routeID inactive]
:if ($status != true) do={
:log info "Secondary WAN is ACTIVE"
/system/scheduler/enable secondary_active_check
/system/scheduler/disable secondary_inactive_check
:local rname [/system identity get name]
:local rdate [/system clock get date]
:local rtime [/system clock get time]
/tool e-mail send to="alerts@mikrotikmasters.com" \
subject="WAN Recovery: Secondary Link Up - $rname" \
body="Router Name: $rname \nDate: $rdate \nTime: $rtime \nStatus: Secondary Link Up"
}
The secondary link uses an identical flip-flop pattern to the primary. Monitoring the secondary link is arguably more important than most people realise — in a dual-WAN setup the secondary link is often overlooked until it’s needed, at which point you discover it’s been down for days. Getting an alert when the secondary drops out means you know your redundancy is compromised before the primary also has a problem, giving you time to act rather than scrambling during an outage with no fallback.
What the email tells you
Each alert email contains four pieces of information:
- Router name — pulled from
/system identity, useful if you’re managing multiple sites from the same mailbox - Date and time — the exact moment the state change was detected, taken directly from the router clock
- Status — one of four states: Primary Link Down, Primary Link Up, Secondary Link Down, Secondary Link Up
- Subject line — prefixed with either
WAN AlertorWAN Recoveryso you can filter and prioritise in your email client without opening the message
Setting it up
Step 1 — configure the email tool using the settings above. You can test it immediately with:
routeros
/tool e-mail send to="admin@mikrotikmasters.com" subject="Test" body="RouterOS email working"
Step 2 — verify your route comments. The scripts find routes by comment text. Check that your recursive default routes are commented correctly:
/ip route print where comment="primary_check"
/ip route print where comment="secondary_check"
/ip route print where comment="primary_route"
/ip route print where comment="secondary_route"
If you use different comment text, update the scripts to match before creating the schedulers.
Step 3 — create all four schedulers under /system scheduler. Set your preferred polling interval — 60 seconds is a reasonable balance between detection speed and resource overhead. Apply the correct default enabled state for each:
| Scheduler | Default state | Watches |
|---|---|---|
primary_active_check | Enabled | Primary route going inactive |
primary_inactive_check | Disabled | Primary route becoming active |
secondary_active_check | Enabled | Secondary route going inactive |
secondary_inactive_check | Disabled | Secondary route becoming active |
Both active-check schedulers start enabled because the assumption at boot is that both links are up. If a link is actually down at boot time, the active-check will detect it on its first run and flip to the inactive-check within one polling interval.
Limitations to be aware of
Polling latency. This is a polling approach, not an event-driven one. With a 60-second interval you could be up to 60 seconds behind the actual failover event. The failover itself happens in seconds via the recursive routing mechanism — the delay is only in the notification.
Router clock accuracy. Timestamps in the email come from the router clock. Ensure /system ntp client is enabled and pointing at a reliable server, otherwise timestamps in alerts may be incorrect.
Email delivery depends on internet access. If both WAN links go down simultaneously, the alert email for the second failure may not send — there’s no internet path to reach the mail server. The local log entry will still be written so you’ll have a record when you next connect directly.
Reboot behaviour. On reboot, all schedulers return to their configured default state — both active-check schedulers enabled, both inactive-check schedulers disabled. If a link was down at the time of reboot, the active-check will detect and flip within one polling cycle after boot, so you’ll still receive an alert, just with a short delay after the router comes back online.



