Metadata-Version: 2.4
Name: imap_reader
Version: 1.0.1
Summary: Simple Python library for reading verification emails via IMAP — OTP extraction, link parsing, auto IMAP detection.
Author-email: nabilunnuha <nabilunnuha@gmail.com>
License: MIT
Project-URL: Homepage, https://github.com/nabilunnuha/imap_reader
Project-URL: Bug Tracker, https://github.com/nabilunnuha/imap_reader/issues
Keywords: imap,email,otp,verification,imap-reader,login-email
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Topic :: Communications :: Email
Requires-Python: >=3.8
Description-Content-Type: text/markdown

# imap_reader

> Simple, clean Python library for reading verification emails via IMAP — with OTP extraction, verification link parsing, and auto IMAP detection.

**Zero external dependencies** — uses Python standard library only (`imaplib`, `email`, `re`, `threading`).

---

## Installation

```bash
pip install git+https://github.com/nabilunnuha/imap_reader.git
```

---

## Quick Start

```python
from imap_reader import LoginEmail

with LoginEmail(
    email_address="user@gmail.com",
    password_email="your_app_password",
) as client:

    for msg in client.get_messages("UNSEEN"):
        print(msg.subject)
        print(msg.otp_codes)           # ['123456']
        print(msg.verification_links)  # ['https://example.com/verify?token=...']
```

---

## Features

- **IMAP auto-detect** — otomatis mendeteksi IMAP host dari domain email
- **OTP extraction** — ekstrak kode 4–8 digit dari isi email
- **Verification link extraction** — temukan dan prioritaskan link verifikasi/konfirmasi
- **HTML email parser** — konversi HTML email ke plain text untuk ekstraksi
- **Login timeout** — raise error jika koneksi melebihi batas waktu (30–60 detik)
- **Context manager** — gunakan `with` statement untuk auto-close koneksi
- **Delete messages** — hapus email berdasarkan kriteria (`ALL`, `SEEN`, `UNSEEN`)
- **Type hints** — fully typed, friendly untuk IDE dan autocomplete

---

## Usage

### Basic — Baca email UNSEEN

```python
from imap_reader import LoginEmail

with LoginEmail("user@gmail.com", "app_password") as client:
    for msg in client.get_messages("UNSEEN"):
        print(f"From    : {msg.sender}")
        print(f"Subject : {msg.subject}")
        print(f"OTP     : {msg.otp_codes}")
        print(f"Links   : {msg.verification_links}")
```

### Ambil hanya 1 email terbaru

```python
with LoginEmail("user@gmail.com", "app_password") as client:
    msg = client.get_latest_message("UNSEEN")
    if msg:
        print(msg.otp_codes)
```

### Custom timeout (30–60 detik direkomendasikan)

```python
with LoginEmail(
    email_address="user@gmail.com",
    password_email="app_password",
    timeout=60,  # detik
) as client:
    msg = client.get_latest_message()
```

### Baca dari folder tertentu

```python
with LoginEmail("user@gmail.com", "app_password") as client:
    for msg in client.get_messages("ALL", folder="SPAM"):
        print(msg.subject)
```

### Hapus email

```python
with LoginEmail("user@gmail.com", "app_password") as client:
    # Hapus semua email yang sudah dibaca
    count = client.delete_messages("SEEN")
    print(f"{count} email dihapus")

    # Hapus semua email di INBOX
    count = client.delete_messages("ALL", folder="INBOX")

    # Hapus email belum dibaca di SPAM
    count = client.delete_messages("UNSEEN", folder="SPAM")
```

### Tambah custom IMAP provider

```python
from imap_reader import LoginEmail
from imap_reader.models import DEFAULT_IMAP_LIST, ImapItemModel

DEFAULT_IMAP_LIST.append(
    ImapItemModel(domain="mycompany.com", imap_host="imap.mycompany.com")
)

with LoginEmail("user@mycompany.com", "password") as client:
    for msg in client.get_messages():
        print(msg)
```

### Error handling

```python
from imap_reader import LoginEmail
from imap_reader.exceptions import (
    AuthenticationError,
    ConnectionTimeoutError,
    ImapNotFoundError,
)

try:
    with LoginEmail("user@gmail.com", "wrong_password", use_default_imap=False, timeout=10) as client:
        msg = client.get_latest_message()
except AuthenticationError:
    print("Email atau password salah.")
except ConnectionTimeoutError:
    print("Koneksi ke server IMAP timeout.")
except ImapNotFoundError:
    print("Domain email tidak dikenali, tambahkan manual ke imap_list.")
```

---

## API Reference

### `LoginEmail(email_address, password_email, imap_list=None, timeout=30)`

| Parameter          | Type   | Default             | Deskripsi                       |
| ------------------ | ------ | ------------------- | ------------------------------- |
| `email_address`    | `str`  | —                   | Alamat email lengkap            |
| `password_email`   | `str`  | —                   | Password IMAP atau App Password |
| `imap_list`        | `list` | `DEFAULT_IMAP_LIST` | List IMAP provider              |
| `use_default_imap` | `bool` | `True`              | Password IMAP atau App Password |
| `timeout`          | `int`  | `30`                | Batas waktu login dalam detik   |

### Methods

| Method                                             | Return                    | Deskripsi                               |
| -------------------------------------------------- | ------------------------- | --------------------------------------- |
| `get_messages(criteria, folder, limit, mark_seen)` | `Generator[EmailMessage]` | Fetch dan yield pesan                   |
| `get_latest_message(criteria, folder)`             | `EmailMessage \| None`    | Ambil 1 pesan terbaru                   |
| `delete_messages(criteria, folder)`                | `int`                     | Hapus pesan, return jumlah yang dihapus |
| `close()`                                          | `None`                    | Tutup koneksi IMAP                      |

**`criteria`** → `Literal["ALL", "SEEN", "UNSEEN"]`  
**`folder`** → `Literal["INBOX", "SENT", "DRAFTS", "TRASH", "SPAM", "JUNK"]`

### `EmailMessage` attributes

| Attribute            | Type        | Deskripsi                          |
| -------------------- | ----------- | ---------------------------------- |
| `uid`                | `str`       | IMAP UID pesan                     |
| `subject`            | `str`       | Subject email (decoded)            |
| `sender`             | `str`       | Pengirim / From header (decoded)   |
| `date`               | `str`       | Tanggal email                      |
| `body_text`          | `str`       | Body plain text                    |
| `body_html`          | `str`       | Body HTML mentah                   |
| `otp_codes`          | `list[str]` | Kode OTP yang ditemukan            |
| `verification_links` | `list[str]` | URL verifikasi (prioritas pertama) |

### Exceptions

| Exception                | Kapan terjadi                  |
| ------------------------ | ------------------------------ |
| `LoginEmailError`        | Base exception                 |
| `AuthenticationError`    | Kredensial salah               |
| `ConnectionTimeoutError` | Login melebihi batas `timeout` |
| `ImapNotFoundError`      | Domain email tidak dikenali    |

---

## Supported Email Providers (auto-detect)

| Provider                 | Domain                                   |
| ------------------------ | ---------------------------------------- |
| Gmail                    | `gmail.com`, `googlemail.com`            |
| Yahoo Mail               | `yahoo.com`, `yahoo.co.id`               |
| Outlook / Hotmail / Live | `outlook.com`, `hotmail.com`, `live.com` |
| iCloud / Me / Mac        | `icloud.com`, `me.com`, `mac.com`        |
| ProtonMail               | `protonmail.com`, `proton.me`            |
| Zoho Mail                | `zoho.com`                               |
| AOL Mail                 | `aol.com`                                |
| Mail.com                 | `mail.com`                               |
| Yandex                   | `yandex.com`, `yandex.ru`                |
| GMX                      | `gmx.com`, `gmx.net`                     |

> Provider lain bisa ditambahkan manual via `ImapItemModel`.

---

## Gmail Setup

Gmail memerlukan **App Password**, bukan password biasa.

1. Buka [Google Account](https://myaccount.google.com/) → **Security**
2. Aktifkan **2-Step Verification**
3. Buka **App Passwords** → Generate password baru
4. Gunakan password tersebut sebagai `password_email`

---

## Project Structure

```
imap_reader/
├── __init__.py      # Public API
├── client.py        # Core IMAP client & LoginEmail class
├── models.py        # ImapItemModel, EmailMessage, DEFAULT_IMAP_LIST
├── parser.py        # OTP, link, HTML extraction utilities
└── exceptions.py    # Custom exceptions
```

---

## License

MIT
