
Pipeline automatizado que resolve domínios de municípios suíços, faz scraping em sites para coletar endereços de e-mail e classifica provedores de e-mail por meio de sondas MX, SPF, DKIM, DMARC e SMTP para mapear dependências digitais.
[!IMPORTANT] O MXmap tem um sucessor. Este projeto evoluiu para um esforço de pesquisa em equipe que cobre todos os municípios da Alemanha, Áustria e Suíça: secassure2026.mxmap-project.org (código-fonte). O mapa suíço em mxmap.ch permanece online, mas seus dados estão congelados em abril de 2026 e não serão atualizados.
Mapas interativos que mostram onde os municípios suíços hospedam seu e-mail e o quão profundamente seu DNS está ligado aos hyperscalers dos EUA (Microsoft, Google, AWS) em comparação com provedores suíços e soluções auto-hospedadas.
O pipeline de dados tem duas etapas:
Resolver domínios — Busca todos os ~2100 municípios suíços na Wikidata e na API do BFS (Estatísticas da Suíça), aplica substituições manuais, extrai endereços de e-mail dos sites municipais, adivinha domínios a partir dos nomes dos municípios e verifica candidatos com consultas MX. Pontua a concordância das fontes para escolher o melhor domínio. Gera municipality_domains.json.
Classificar provedores — Para cada domínio resolvido, consulta todos os hosts MX, aplica correspondência de padrões e executa 10 sondas concorrentes (SPF, DKIM, DMARC, Autodiscover, cadeia CNAME, banner SMTP, Tenant, ASN, verificação TXT, IP SPF). Agrega evidências ponderadas e calcula pontuações de confiança (0–100). Gera data.json (completo) e data.min.json (minificado para o frontend).
flowchart TD
subgraph resolve ["1 · Resolve domains"]
bfs[/"BFS Statistics API"/] --> merge["Merge ~2100 municipalities"]
wikidata[/"Wikidata SPARQL"/] --> merge
overrides[/"overrides.json"/] --> per_muni
merge --> per_muni["Per municipality"]
per_muni --> scrape["Scrape website for<br/>email addresses"]
per_muni --> guess["Guess domains<br/>from name"]
scrape --> mx_verify["MX lookup to<br/>verify domains"]
guess --> mx_verify
mx_verify --> score["Score source<br/>agreement"]
end
score --> domains[("municipality_domains.json")]
domains --> classify_in
subgraph classify ["2 · Classify providers"]
classify_in["Per unique domain"] --> mx_lookup["MX lookup<br/>(all hosts)"]
mx_lookup --> mx_match["Pattern-match MX<br/>+ detect gateway"]
mx_match --> concurrent["10 concurrent probes<br/>SPF · DKIM · DMARC<br/>Autodiscover · CNAME chain<br/>SMTP · Tenant · ASN<br/>TXT verification · SPF IP"]
concurrent --> aggregate["Aggregate weighted<br/>evidence"]
aggregate --> vote["Primary vote<br/>+ confidence scoring"]
end
vote --> data[("data.json + data.min.json")]
data --> frontend["Leaflet map<br/>mxmap.ch"]
consulte classifier.py para os detalhes completos da implementação, mas, em resumo,
usamos um sistema de evidências ponderadas em que cada sonda contribui com sinais de intensidade variada para diferentes classificações de provedores.
uv sync
# Stage 1: resolve municipality domains
uv run resolve-domains
# Stage 2: classify email providers
uv run classify-providers
# Serve the map locally
python -m http.server
uv sync --group dev
# Run tests (90% coverage threshold enforced)
uv run pytest --cov --cov-report=term-missing
# Lint & format
uv run ruff check src tests
uv run ruff format src tests
Forks específicos por país, em ordem alfabética pelo código do país:
Novos forks de países são bem-vindos — considere começar pelo pipeline do sucessor, que adiciona uma etapa de varredura DANE/DNSSEC/SPF/DMARC.
Projetos relacionados:
Veja também os forks deste repositório.
Se você identificar uma classificação incorreta, abra uma issue com o número BFS e o provedor correto.
Para municípios em que a detecção automatizada falha, as correções podem ser adicionadas em overrides.json.