It’s… erm… not nice. One thing is all the bridges, it’s not recommended way (see e.g. this popular thread), but it should work too (I didn’t examine all details).
As for firewall, it’s not better. There’s no problem with filter, e.g. 192.168.131.x connecting to 192.168.128.232:587 will jump to mx-web chain and will be allowed there. You even have more than one jump rule that will do it, either the first “Allow wifi/iot access to printer/servers” or following one with dst-address=192.168.128.232. And that’s it, happy end. Well, it would be, if it wasn’t for your unnecessary (for this) and wrong hairpin NAT rule:
/ip firewall nat
add action=masquerade chain=srcnat comment="hairpin NAT" dst-address=192.168.128.0/22 log-prefix=hairpin protocol=tcp src-address=192.168.128.0/22 to-addresses=192.168.128.240/30
This takes any traffic between any local subnets passing through router and changes source to 192.168.128.240-3. So server will see incoming connections from those addresses and will try to respond to local devices that have them, not to router. If you need any hairpin NAT at all, it would be one of (note the masks):
/ip firewall nat
add chain=srcnat dst-address=192.168.128.0/24 src-address=192.168.128.0/24 action=masquerade
add chain=srcnat dst-address=192.168.128.0/24 src-address=192.168.128.0/24 action=src-nat to-addresses=x.x.x.x
Where x.x.x.x can be pretty much anything except 192.168.128.x (192.168.128.1 would work, but then it’s easier to use first rule with masquerade).
Edit: Actually, RouterOS got me again, it mistakenly keeps to-addresses from previous action=src-nat when you change it to action=masquerade. So it should work as is, only connections will show up as from 192.168.128.1 (you’re still masquerading traffic that doesn’t need to be masqueraded).
Edit2: Nah, on yet another look, it’s mainly the routing rule where you say that anything from 192.168.128.232 should use toVDSL routing table.