All posts
    Tutorials

    Selenium Email Testing: Automate Verification in Java and Python

    The Devmailr Team7 min read

    Selenium is still the workhorse for cross-browser and legacy suites, but like any browser driver it can’t read email. Here’s how to test email verification with Selenium — in Java and Python — by reading the message from a disposable inbox API.

    The approach

    Selenium drives the browser; a disposable inbox API gives you the email. The pattern: create an inbox via Devmailr, drive the signup form with its address, then make one HTTP call to wait for the verification email and read the code.

    Java (Selenium + java.net.http)

    Using the JDK’s built-in HttpClient and Jackson for JSON:

    java
    String base = "https://api.devmailr.app/api";
    String auth = "Bearer " + System.getenv("DEVMAILR_API_KEY");
    HttpClient http = HttpClient.newHttpClient();
    ObjectMapper mapper = new ObjectMapper();
    
    // 1. Create a disposable inbox
    String body = """
        {"prefix": "sel-%d"}""".formatted(System.currentTimeMillis());
    JsonNode inbox = mapper.readTree(http.send(
        HttpRequest.newBuilder(URI.create(base + "/mailboxes"))
            .header("Authorization", auth).header("Content-Type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString(body)).build(),
        HttpResponse.BodyHandlers.ofString()).body());
    String id = inbox.get("_id").asText();
    String address = inbox.get("address").asText();
    
    // 2. Drive the signup form
    driver.get("https://staging.myapp.com/signup");
    driver.findElement(By.name("email")).sendKeys(address);
    driver.findElement(By.name("password")).sendKeys("correct-horse-battery-staple");
    driver.findElement(By.cssSelector("button[type=submit]")).click();
    
    // 3. Wait for the verification email (server long-polls up to 60s)
    JsonNode email = mapper.readTree(http.send(
        HttpRequest.newBuilder(URI.create(base + "/mailboxes/" + id + "/wait?has_code=true&timeout=60"))
            .header("Authorization", auth).timeout(Duration.ofSeconds(65)).build(),
        HttpResponse.BodyHandlers.ofString()).body());
    String code = email.get("extractedCodes").get(0).asText();
    
    // 4. Enter the code
    driver.findElement(By.name("code")).sendKeys(code);
    driver.findElement(By.cssSelector("button[type=submit]")).click();

    Python (Selenium + requests)

    python
    import os, time, requests
    from selenium import webdriver
    from selenium.webdriver.common.by import By
    
    BASE = "https://api.devmailr.app/api"
    AUTH = {"Authorization": f"Bearer {os.environ['DEVMAILR_API_KEY']}"}
    
    # 1. Create a disposable inbox
    inbox = requests.post(f"{BASE}/mailboxes", headers=AUTH,
                          json={"prefix": f"sel-{int(time.time())}"}).json()
    
    driver = webdriver.Chrome()
    driver.get("https://staging.myapp.com/signup")
    driver.find_element(By.NAME, "email").send_keys(inbox["address"])
    driver.find_element(By.NAME, "password").send_keys("correct-horse-battery-staple")
    driver.find_element(By.CSS_SELECTOR, "button[type=submit]").click()
    
    # 2. Wait for the verification email (give requests a read timeout above the wait)
    email = requests.get(f"{BASE}/mailboxes/{inbox['_id']}/wait", headers=AUTH,
                         params={"has_code": "true", "timeout": 60}, timeout=65).json()
    code = email["extractedCodes"][0]
    
    driver.find_element(By.NAME, "code").send_keys(code)
    driver.find_element(By.CSS_SELECTOR, "button[type=submit]").click()
    
    # 3. Clean up
    requests.delete(f"{BASE}/mailboxes/{inbox['_id']}", headers=AUTH)

    For a click-to-verify link, read primaryLink and point Selenium at it:

    python
    email = requests.get(f"{BASE}/mailboxes/{inbox['_id']}/wait", headers=AUTH,
                         params={"timeout": 60}, timeout=65).json()
    driver.get(email["primaryLink"])

    Tips

    • The /wait endpoint long-polls, so set your HTTP client’s read timeout above the wait timeout (Python timeout=65; Java .timeout(Duration.ofSeconds(65))).
    • Use a unique prefix per run (a timestamp) for parallel safety.
    • Keep DEVMAILR_API_KEY in an env var / CI secret.

    Related reading

    Try it in two minutes

    Create a disposable prefix@devmailr.app inbox over the API, send mail to it from your app, and read it in your tests. Free plan, no card required.