Skip to content
Starten Sie mit 100 kostenlosen Verifizierungs-Credits
Qualisend
Alle Artikel
Engineering / 16. Juni 2026

E-Mail-Adressen in Ruby validieren: so geht's

7 minutes read

Qualisend team
Ein Code-Editor-Fenster mit dem Titel validate.rb, einem roten Ruby-Edelstein-Symbol und einer grünen Pille mit dem Ergebnis „zustellbar“, darüber die Bildunterschrift Syntax zu MX zu Postfach.

Eine E-Mail-Adresse in Ruby zu validieren sind drei Aufgaben, die sich hinter einem einzigen Methodennamen verstecken. Die meisten Tutorials reichen Ihnen eine Regex, sehen zu, wie sie durchläuft, und erklären die Adresse für gültig — aber ein Musterabgleich sagt Ihnen nur, dass die Zeichenkette die richtige Form hat, nicht dass jemals Post bei ihr ankommt. Echte Validierung ist geschichtet: eine günstige Syntaxprüfung, ein DNS-Lookup nach den Mailservern der Domain und ein SMTP-Test des tatsächlichen Postfachs. Rubys Standardbibliothek liefert Ihnen die ersten beiden ganz ohne Gems; die dritte ist ein Netzwerkproblem, das man besser abgibt. Dieser Leitfaden baut jede Schicht mit funktionierendem Code auf und zeigt genau, wo die Standardbibliothek aufhört.

Die kurze Antwort#

Verwenden Sie URI::MailTo::EMAIL_REGEXP aus der uri-Bibliothek für die Syntax, Resolv::DNS aus der resolv-Bibliothek für den MX-Lookup und eine Verifizierungs-API für die SMTP-Postfachprüfung — das Günstigste zuerst, mit Kurzschluss, sobald eine Schicht entscheidend ist. Greifen Sie nicht zu net/smtp, um Postfächer von Ihrer eigenen App aus zu testen: Der ausgehende Port 25 ist auf den meisten Hostern blockiert, und die Antwort hängt von der Reputation Ihrer sendenden IP und einem Greylisting-Verhalten ab, das Sie nicht selbst nachbauen wollen. Jede Schicht schließt Adressen günstiger aus als die vorige; nur die letzte kann eine Adresse einschließen. Genau diese letzte Lücke existiert die E-Mail-Verifizierung, um sie zu schließen.

Schicht 1: Syntax#

Regex gehört hierher und nirgendwo sonst — und in Ruby müssen Sie nicht einmal selbst eine schreiben. Die uri-Bibliothek, Teil der Standardbibliothek, liefert ein gut getestetes Muster in URI::MailTo::EMAIL_REGEXP mit, greifen Sie also dazu, statt etwas von Stack Overflow zu kopieren:

require "uri"

def valid_syntax?(email)
  email.is_a?(String) &&
    email.length <= 320 &&
    email.match?(URI::MailTo::EMAIL_REGEXP)
end
valid_syntax?("jane@example.com")  # => true
valid_syntax?("not-an-email")      # => false
valid_syntax?("a@@b.com")          # => false

Zwei Dinge sollten Sie über diese Konstante wissen. Sie ist bereits mit \A und \z verankert, sodass match? die ganze Zeichenkette prüft statt einer Teilzeichenkette — Sie müssen sie nicht selbst umschließen oder verankern. Und sie ist bewusst großzügig: Sie folgt der WHATWG/HTML5-Definition einer gültigen E-Mail, die lockerer ist als RFC 5322, und akzeptiert zum Beispiel bereitwillig jane@localhost, weil sie keinen Punkt in der Domain verlangt. Das ist ein Feature, kein Bug. Die Aufgabe von Schicht eins ist es, Tippfehler bei der Eingabe abzufangen, nicht die RFCs auszufechten — was ohnehin nicht helfen würde. Die 320-Zeichen-Grenze ist doppelte Absicherung: Nichts Längeres kann eine echte Adresse sein, und es ist günstiger, früh abzulehnen, als eine riesige Zeichenkette weiterzureichen. Ein Durchlauf hier bedeutet „prüfenswert“, niemals „gültig“.

Schicht 2: Kann die Domain überhaupt Post empfangen?#

Hier verdient sich Rubys Standardbibliothek ihr Geld. Eine Domain ohne Mailroute kann für niemanden Post annehmen, sodass ein einziger MX-Lookup tote Domains, falsch geschriebene Firmennamen und erfundene TLDs aussortiert. Die resolv-Bibliothek löst Records ohne Gems auf:

require "resolv"

def mail_route?(domain)
  records = Resolv::DNS.open do |dns|
    dns.getresources(domain, Resolv::DNS::Resource::IN::MX)
  end
  !records.empty?
rescue Resolv::ResolvError, Resolv::ResolvTimeout
  false
end
mail_route?("gmail.com")               # => true
mail_route?("company-that-folded.com") # => false

Resolv::DNS.open gibt Ihnen einen Resolver und schließt ihn, wenn der Block endet, und getresources liefert ein Array von MX-Records zurück — ein leeres Array, wenn die Domain keine veröffentlicht oder nicht existiert, was genau der „keine Route“-Fall ist, den Sie abfangen wollen. Das rescue behandelt den anderen Fehlerfall: einen Resolver, der einen Fehler wirft oder in ein Timeout läuft. Beachten Sie, dass Resolv::ResolvTimeout keine Unterklasse von Resolv::ResolvError ist, benennen Sie also beide, wenn ein langsamer Nameserver sauber durchfallen soll, statt den Aufruf zu sprengen.

Wenn Sie die tatsächlichen Mailhosts statt eines Ja/Nein wollen — um sie zu protokollieren oder Prioritäten zu prüfen — trägt jeder Record exchange und preference, sortieren Sie also nach Letzterem:

def mail_hosts(domain)
  records = Resolv::DNS.open do |dns|
    dns.getresources(domain, Resolv::DNS::Resource::IN::MX)
  end
  records.sort_by(&:preference).map { |mx| mx.exchange.to_s }
  # => ["gmail-smtp-in.l.google.com", "alt1.gmail-smtp-in.l.google.com", ...]
rescue Resolv::ResolvError, Resolv::ResolvTimeout
  []
end

Manche Domains nehmen Post über einen A-Record mit implizitem MX an; wenn Sie diesen Sonderfall berücksichtigen müssen, weichen Sie auf getresources(domain, Resolv::DNS::Resource::IN::A) aus, wenn die MX-Menge leer zurückkommt. Für die überwältigende Mehrheit echter Adressen ist eine MX-Prüfung der richtige Filter.

Schicht 3: Existiert das Postfach tatsächlich?#

Die Schichten eins und zwei können eine Adresse nur ausschließen. Eine Domain kann perfekte MX-Records veröffentlichen und trotzdem kein Postfach unter der Adresse haben, die Sie in Händen halten — noreply-9f2x@gmail.com ist gültige Syntax auf einer aktiven Mailroute, und es ist trotzdem ein Postfach, das nie angelegt wurde. Zu bestätigen, dass ein bestimmtes Postfach existiert, bedeutet die SMTP-Zustellkonversation: sich mit dem Mailhost verbinden, RCPT TO ausgeben, die Antwort lesen und trennen, bevor irgendetwas gesendet wird. Da steckt mehr dahinter — wie E-Mail-Verifizierung funktioniert geht die vollständige Pipeline durch, einschließlich Catch-all-Domains, die jede Adresse akzeptieren und einen naiven Test aushebeln.

Rubys Standardbibliothek öffnet diese Konversation mit net/smtp bereitwillig für Sie. Das Problem ist nicht der Code; es ist das Netzwerk. Führen Sie einen SMTP-Test von Ihrem Anwendungsserver aus, und drei Dinge gehen schief: Die meisten Cloud-Anbieter blockieren den ausgehenden Port 25 vollständig, die Antwort hängt von der Reputation der IP ab, von der aus Sie sich verbinden, und empfangende Server greylisten und drosseln unbekannte Absender — sodass ein Test, der auf Ihrem Laptop funktioniert, in der Produktion klammheimlich fehlschlägt oder Sie auf eine Blocklist bringt. Das ist die Schicht, die sich zu delegieren lohnt.

Die vollständige Prüfung mit einer API#

Der Verifizierungs-Endpunkt von Qualisend führt die ganze Pipeline aus — Syntax, DNS und den SMTP-Postfachtest — von einer reputationsverwalteten Infrastruktur, die dafür gebaut ist, und liefert ein einziges Urteil zurück. Da es ein schlichter JSON-POST ist, deckt das net/http der Standardbibliothek ihn ganz ohne Gems ab. Lesen Sie Ihren Schlüssel aus der Umgebung, statt ihn fest zu verdrahten:

require "net/http"
require "json"
require "uri"

VERIFY_URL = URI("https://api.qualisend.com/v1/verify")

def verify(email)
  request = Net::HTTP::Post.new(VERIFY_URL)
  request["Authorization"] = "Bearer #{ENV.fetch('QUALISEND_API_KEY')}"
  request["Content-Type"]  = "application/json"
  request.body = JSON.generate(email: email)

  response = Net::HTTP.start(VERIFY_URL.hostname, VERIFY_URL.port, use_ssl: true) do |http|
    http.request(request)
  end

  raise "Qualisend responded #{response.code}" unless response.is_a?(Net::HTTPSuccess)

  JSON.parse(response.body, symbolize_names: true)
end

Dieser Endpunkt ist ein Platzhalter — schauen Sie in die API-Referenz für die genaue Basis-URL, die Form der Anfrage und wie Sie einen mit Scopes versehenen Schlüssel erzeugen. Die Antwort umschließt ein result-Objekt:

{
  "result": {
    "status": "deliverable",
    "score": 95,
    "reason": null,
    "sub_flags": { "role": false, "disposable": false, "catch_all": false }
  }
}

Greifen Sie in den Umschlag und handeln Sie nach status:

body   = verify("jane@example.com")
result = body[:result]

result[:status]    # "deliverable" | "risky" | "undeliverable" | "unknown"
result[:score]     # confidence, 0–100
result[:reason]    # machine-readable reason, or nil
result[:sub_flags] # { role:, disposable:, catch_all:, ... }

net/http hält das abhängigkeitsfrei, was in einem Hintergrund-Job oder einem kleinen Service praktisch ist. Wenn Ihre App bereits auf Faraday oder HTTParty setzt, ist dieselbe Anfrage ein paar Zeilen kürzer — der Umschlag, den Sie zurücklesen, ist identisch.

Ein vollständiger Weg, eine E-Mail-Adresse in Ruby zu validieren#

Verketten Sie die drei Schichten günstigstes-zuerst und stoppen Sie in dem Moment, in dem eine entscheidend ist:

def validate_email(email)
  return { status: "undeliverable", reason: "invalid_email" } unless valid_syntax?(email)

  domain = email.rpartition("@").last
  return { status: "undeliverable", reason: "invalid_domain" } unless mail_route?(domain)

  verify(email)[:result] # deliverable | risky | undeliverable | unknown
end

rpartition("@") teilt am letzten @, sodass Sie immer die echte Domain nehmen, selbst bei seltsam gequoteten lokalen Teilen. Die beiden lokalen Schichten kosten nichts und fangen den meisten Schrott sofort ab; die API läuft nur auf Adressen, die den Netzwerk-Roundtrip wert sind. Genau diese Reihenfolge — nicht die Sprache — macht Validierung zuverlässig, und es ist dieselbe Form, die Sie in den Node.js- und Python-Versionen dieses Leitfadens finden.

Rails-Nutzer können das Ganze als benutzerdefinierte Validierung in ein Model fallen lassen, sodass eine schlechte Adresse nie die Datenbank erreicht:

class User < ApplicationRecord
  validate :email_must_be_deliverable

  private

  def email_must_be_deliverable
    return if email.blank?

    verdict = validate_email(email)
    errors.add(:email, "doesn't look deliverable") if verdict[:status] == "undeliverable"
  end
end

Halten Sie den synchronen Pfad auf den beiden schnellen lokalen Schichten plus dem unmittelbaren API-Urteil; alles Langsamere gehört in einen Hintergrund-Job. Aber der Kern ist schlichtes Ruby, und er verhält sich in einer Sinatra-Route, einer Rake-Task oder einem einmaligen Skript gleich — die Schichtung ist es, die die Arbeit erledigt.

Häufig gestellte Fragen#

Kann ich in Ruby eine E-Mail-Adresse ohne Gems validieren?#

Für zwei der drei Schichten ja. URI::MailTo::EMAIL_REGEXP aus der uri-Bibliothek übernimmt die Syntax, und Resolv::DNS aus der resolv-Bibliothek löst MX-Records auf — beide sind bei Ruby dabei, sodass eine Syntax-plus-Domain-Prüfung ohne jede Installation auskommt. Die dritte Schicht, das Postfach selbst zu bestätigen, bedeutet einen SMTP-Test, den Sie nicht von Ihrem eigenen Server ausführen sollten. Genau diesen Teil übernimmt ein Verifizierungsdienst für Sie.

Reicht URI::MailTo::EMAIL_REGEXP für sich allein aus?#

Es ist die richtige Prüfung für Schicht eins und eine weit bessere Wahl als eine selbstgebastelte Regex — aber es validiert die Form, nicht die Zustellbarkeit. Es löst nie DNS auf und kontaktiert keinen Mailserver, und es ist bewusst großzügig (es akzeptiert jane@localhost), sodass ein Durchlauf „sieht aus wie eine E-Mail“ bedeutet, nicht „wird zugestellt“. Kombinieren Sie es mit einem MX-Lookup und einer Postfachprüfung, bevor Sie der Adresse vertrauen.

Warum nicht net/smtp verwenden, um zu prüfen, ob ein Postfach existiert?#

net/smtp kann die SMTP-Konversation öffnen, aber sie von Ihrem Anwendungsserver aus auszuführen ist unzuverlässig und riskant: Die meisten Hoster blockieren den ausgehenden Port 25, die Antwort hängt von der Reputation Ihrer sendenden IP ab, und Tests in jeglichem Umfang führen zu Rate-Limits oder Blocklistung. Eine Verifizierungs-API führt den Test von einer reputationsverwalteten Infrastruktur aus, die genau dafür gebaut ist.

Sollte ich E-Mails bei der Anmeldung oder beim Bereinigen einer Liste validieren?#

Beides, in unterschiedlicher Tiefe. Führen Sie Syntax und den MX-Lookup synchron bei der Anmeldung aus — sie sind schnell genug, um die Anfrage zu blockieren und sofortiges Feedback zu geben — und handeln Sie dort auch nach dem unmittelbaren API-Urteil. Reservieren Sie tiefere, langsamere Arbeit für die Listenbereinigung und Back-Office-Aufgaben; der Serverless-Anmeldeleitfaden zeigt das Live-Muster von Anfang bis Ende.


Bereit, die Postfach-Schicht hinzuzufügen? Die API-Referenz hat den /verify-Endpunkt, mit Scopes versehene Schlüssel und Copy-and-paste-Snippets, oder fügen Sie eine Adresse in den kostenlosen E-Mail-Checker ein und sehen Sie zu, wie eine syntaktisch perfekte Zeichenkette als unzustellbar zurückkommt.

Your reputation, protected.

Clean your first list in minutes. 100 free credits, no card required.

Get started