# TestFly Part 10: Email & 2FA Testing with Mailhog, Mailtrap & IMAP

URL: https://hakangul.lovable.app/blog/testfly-part-10-email-and-2fa-testing-mailhog-mailtrap-imap
Author: Hakan Gül — Team Lead Senior Test Automation Engineer
Published: 2026-09-10
Updated: 2026-09-10
Category: test-automation
Tags: TestFly, Email Testing, Mailhog, Mailtrap, 2FA, Java, SDET

> Automate user registration, password resets, and 2FA authentication in Java using TestFly's built-in Mailhog, Mailtrap, and IMAP email testing engine.

## English

**TL;DR:** End-to-end user registration, password resets, and two-factor authentication (2FA) flows frequently fail because testing email delivery is cumbersome. TestFly bundles built-in mailbox clients for Mailhog, Mailtrap, Outlook Graph, and generic IMAP, allowing SDETs to fetch incoming emails, parse OTP codes via regex, and click verification links in a single automated test.

---

## Why Is Email Verification a Critical Bottleneck in E2E Automation?

Almost every SaaS platform requires email validation during signup or sensitive operations. Traditional automation suites struggle with this because:
- Public inboxes (like Gmail) enforce rate limits, CAPTCHAs, and bot detection.
- Developers often disable email verification in test environments, creating significant blind spots for production regressions.
- Third-party email libraries require complex MIME parsing, socket handling, and manual wait loops.

TestFly provides the `email()` helper directly on `BaseTest`, abstracting all protocol details and integrating asynchronous polling with the central `WaitEngine`.

---

## How Does TestFly Connect to Mailboxes?

TestFly supports local development mailcatchers and enterprise cloud providers through simple configuration in `testfly.yml`:

```yaml title="testfly.yml"
email:
  provider: mailhog # options: mailhog, mailtrap, outlook, imap
  host: localhost
  port: 8025
  pollIntervalSeconds: 2
  timeoutSeconds: 30
```

---

## How to Test Signup with 2FA / OTP in Java?

Here is a complete, working example that signs up on a WebUI, waits for the verification email, extracts the 6-digit OTP code, and completes the login:

```java
package io.testfly.examples.email;

import io.testfly.email.EmailMessage;
import io.testfly.test.BaseTest;
import org.testng.annotations.Test;

public class EmailVerificationTest extends BaseTest {

    @Test
    public void testUserRegistrationWithEmailConfirmation() {
        String testEmail = "user_" + System.currentTimeMillis() + "@testfly.local";

        // 1. Fill registration form on WebUI
        open("/register");
        find("#email-input").type(testEmail);
        find("#submit-btn").click();

        // 2. Wait for confirmation email to arrive
        EmailMessage message = email().waitForMessage(query -> 
            query.to(testEmail).subjectContains("Welcome to TestFly")
        );

        // 3. Extract OTP code or activation link via Regex
        String otpCode = message.extractRegex("Your verification code is: (\\d{6})");

        // 4. Enter OTP in browser and confirm
        find("#otp-input").type(otpCode);
        find("#verify-btn").click();

        assertThat(find("#welcome-banner")).isVisible();
    }
}
```

---

## What Mail Providers Are Supported?

| Provider | Protocol | Typical Use Case |
|:---|:---|:---|
| **Mailhog** | HTTP REST API | Local Docker environments, CI/CD runners |
| **Mailtrap** | REST API & SMTP | Staging environments, shared team sandboxes |
| **Outlook Graph** | Microsoft Graph API | Enterprise Office 365 test mailboxes |
| **Generic IMAP** | SSL/TLS IMAP | Custom corporate email servers |

---

## FAQ

### Does TestFly poll the mailbox asynchronously?
Yes. TestFly checks the inbox at configurable intervals until the expected message matching your criteria arrives or the timeout is exceeded.

### Can I extract HTML links and click them directly?
Yes. `message.extractLink("Confirm Email")` extracts the verification URL, allowing you to navigate to it immediately with `open(url)`.

### Does this work with temporary throwaway email addresses?
Yes. You can generate dynamic inbox aliases (e.g. `user+123@domain.com`) and query them specifically with `query.to(...)`.

## Türkçe

**Özet:** Kullanıcı kaydı, şifre sıfırlama ve iki faktörlü kimlik doğrulama (2FA) süreçleri uçtan uca testlerin en sık tıkandığı alanlardır. TestFly; Mailhog, Mailtrap, Outlook Graph ve genel IMAP protokollerini dahili olarak destekleyerek gelen kutusunu otomatik sorgulama, regex ile OTP kodlarını ayıklama ve doğrulama linklerine tıklama işlemlerini tek satıra indirir.

---

## E-Posta Doğrulaması Neden E2E Testlerin En Büyük Tıkanma Noktasıdır?

Hemen hemen her modern web uygulamasında kayıt olurken veya hassas işlemlerde e-posta onayı zorunludur. Geleneksel otomasyon projelerinde bu durum şu zorlukları yaratır:
- Gerçek e-posta sağlayıcıları (Gmail, Outlook) bot korumaları, CAPTCHA ve istek sınırları koyar.
- Ekipler çoğu zaman test ortamlarında e-posta doğrulamasını kapatır; bu da canlı ortamda kritik güvenlik açıklarının ve regresyonların gözden kaçmasına yol açar.
- Harici kütüphaneler karmaşık MIME ayrıştırma kodları ve manuel `Thread.sleep()` döngüleri gerektirir.

TestFly, `BaseTest` üzerinden doğrudan erişilebilen `email()` yardımcı motoruyla bu karmaşıklığı ortadan kaldırır.

---

## TestFly E-Posta Sunucusuna Nasıl Bağlanır?

`testfly.yml` dosyasına ekleyeceğiniz tek bir blokla sağlayıcınızı tanımlayabilirsiniz:

```yaml title="testfly.yml"
email:
  provider: mailhog # mailhog, mailtrap, outlook, imap
  host: localhost
  port: 8025
  pollIntervalSeconds: 2
  timeoutSeconds: 30
```

---

## 2FA / OTP Doğrulama Senaryosu Nasıl Yazılır?

Aşağıdaki örnekte kullanıcı arayüzünde kayıt formunu dolduran, gelen kutusunu dinleyen, 6 haneli doğrulama kodunu alan ve tarayıcıya girerek işlemi tamamlayan senaryo gösterilmektedir:

```java
package io.testfly.examples.email;

import io.testfly.email.EmailMessage;
import io.testfly.test.BaseTest;
import org.testng.annotations.Test;

public class EpostaDogrulamaTesti extends BaseTest {

    @Test
    public void kullaniciKaydiVeIkiFaktorluDogrulama() {
        String testEpostasi = "test_" + System.currentTimeMillis() + "@testfly.local";

        // 1. Kayıt formunu doldur
        open("/register");
        find("#email-input").type(testEpostasi);
        find("#submit-btn").click();

        // 2. Gelen doğrulama e-postasını bekle
        EmailMessage eposta = email().waitForMessage(sorgu -> 
            sorgu.to(testEpostasi).subjectContains("TestFly Hoş Geldiniz")
        );

        // 3. Regex ile 6 haneli OTP kodunu ayrıştır
        String otpKodu = eposta.extractRegex("Doğrulama kodunuz: (\\d{6})");

        // 4. Kodu tarayıcıya gir ve doğrula
        find("#otp-input").type(otpKodu);
        find("#verify-btn").click();

        assertThat(find("#welcome-banner")).isVisible();
    }
}
```

---

## Hangi E-Posta Sağlayıcıları Desteklenir?

| Sağlayıcı | Protokol | Kullanım Alanı |
|:---|:---|:---|
| **Mailhog** | HTTP REST API | Lokal Docker ortamları, CI/CD pipeline'ları |
| **Mailtrap** | REST API & SMTP | Staging ve paylaşımlı test ortamları |
| **Outlook Graph** | Microsoft Graph API | Kurumsal Office 365 e-posta hesapları |
| **Genel IMAP** | SSL/TLS IMAP | Özel şirket içi e-posta sunucuları |

---

## SSS

### TestFly gelen kutusunu asenkron olarak bekler mi?
Evet. `email().waitForMessage()` metodu, aranan kriterlere uyan e-posta gelene kadar arka planda asenkron sorgulama yapar ve zaman aşımı durumunda bilgilendirici hata üretir.

### E-posta içindeki onay butonuna doğrudan tıklanabilir mi?
Evet. `eposta.extractLink("Hesabımı Onayla")` metodu HTML içindeki linki otomatik yakalar ve `open(link)` ile doğrudan sayfaya gidilebilir.

### Dinamik e-posta takma adları (alias) kullanılabilir mi?
Evet. `kullanici+test1234@alanadi.com` gibi dinamik adresler üretilip `sorgu.to(...)` filtresi ile tekilleştirilebilir.
