Email Sender ini Mencakup::

·       🎯 Limit harian per SMTP
·       ⚡ Pengiriman paralel (multithreading)
·       🔄 Auto‑rotate subject
·       ⏸️ Auto‑pause jika terlalu banyak gagal
·       📝 Logging + failed list
·       🔀 Rotasi SMTP random
·       🕒 Delay random antar email

Dan tetap aman untuk SendGrid, Mailgun, Office365.
Agar tetap mudah dipahami, aku susun script ini modular dan rapi.

🧠 Konsep Fitur

1) Limit Harian per SMTP

Di smtp.txt, kamu bisa menambahkan limit harian:

smtp.sendgrid.net|587|apikey|SG.xxxxx|100
smtp.mailgun.org|587|postmaster@domain.com|pwd123|300
smtp.office365.com|587|email@domain.com|pwd456|200
HOST|PORT|USER|PASS|LIMIT_HARIAN

2) Auto‑Rotate Subject

Buat file subject.txt:

Promo Terbaru Untuk Anda
Diskon Spesial Minggu Ini
Penawaran Eksklusif Member

Script akan memilih subject secara acak setiap email.

3) Auto‑Pause

Jika gagal berturut‑turut lebih dari 5 kali, script akan pause 10 menit.

4) Parallel Sending

Kita pakai ThreadPoolExecutor agar bisa kirim paralel, tapi tetap aman karena:

·       Ada delay random
·       SMTP dipilih random
·       Limit harian 

🧪 SCRIPT PYTHON SUPER LENGKAP

Simpan sebagai: mailer.py

import smtplib
import random
import time
from datetime import datetime
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from concurrent.futures import ThreadPoolExecutor

# --- Load SMTP list ---
smtp_list = []
with open("smtp.txt", "r") as f:
    for line in f:
        if line.strip():
            host, port, user, pwd, limit = line.strip().split("|")
            smtp_list.append({
                "host": host,
                "port": int(port),
                "user": user,
                "password": pwd,
                "limit": int(limit),
                "sent_today": 0
            })

# --- Load contact list ---
with open("contact.txt", "r") as f:
    recipients = [line.strip() for line in f if line.strip()]

# --- Load HTML message ---
with open("promote.txt", "r", encoding="utf-8") as f:
    html_content = f.read()

# --- Load subjects ---
with open("subject.txt", "r", encoding="utf-8") as f:
    subjects = [line.strip() for line in f if line.strip()]

FROM_EMAIL = "kamu@domainmu.com"

# --- Logging helper ---
def log(message):
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    with open("log.txt", "a", encoding="utf-8") as logf:
        logf.write(f"[{timestamp}] {message}\n")
    print(message)

# --- Save failed emails ---
def save_failed(email, error):
    with open("failed.txt", "a", encoding="utf-8") as ff:
        ff.write(f"{email} | {error}\n")
# --- Auto pause ---
fail_streak = 0

def send_email(to_email):
    global fail_streak

    # Pilih SMTP yang masih punya limit
    available_smtp = [s for s in smtp_list if s["sent_today"] < s["limit"]]
    if not available_smtp:
        log("Semua SMTP mencapai limit harian. STOP.")
        return

    smtp = random.choice(available_smtp)
    smtp["sent_today"] += 1

    subject = random.choice(subjects)

    msg = MIMEMultipart("alternative")
    msg["Subject"] = subject
    msg["From"] = FROM_EMAIL
    msg["To"] = to_email
    msg.attach(MIMEText(html_content, "html"))

    try:
        server = smtplib.SMTP(smtp["host"], smtp["port"])
        server.starttls()
        server.login(smtp["user"], smtp["password"])
        server.sendmail(FROM_EMAIL, to_email, msg.as_string())
        server.quit()

        log(f"[OK] {to_email} via {smtp['host']} | Subject: {subject}")
        fail_streak = 0

    except Exception as e:
        error_msg = str(e)
        log(f"[FAIL] {to_email} via {smtp['host']} -> {error_msg}")
        save_failed(to_email, error_msg)
        fail_streak += 1

        if fail_streak >= 5:
            log("Terlalu banyak gagal berturut-turut. Auto-pause 10 menit...")
            time.sleep(600)
            fail_streak = 0

    # Delay random 5–15 detik
    delay = random.randint(5, 15)
    log(f"Delay {delay} detik...")
    time.sleep(delay)

# --- Parallel sending ---
THREADS = 3  # jumlah thread paralel

with ThreadPoolExecutor(max_workers=THREADS) as executor:
    executor.map(send_email, recipients)

🎯 Penjelasan Singkat

✔ Limit Harian

Setiap SMTP punya counter sent_today. Jika limit tercapai → tidak dipakai lagi.

✔ Parallel Sending

ThreadPoolExecutor menjalankan beberapa pengiriman sekaligus, tapi tetap aman karena:

·       Delay random
·       SMTP random
·       Limit harian

✔ Auto‑Rotate Subject

Setiap email memakai subject berbeda dari subject.txt.

✔ Auto‑Pause

Jika gagal 5 kali berturut‑turut → pause 10 menit.

🚀 Mau ditambah fitur lagi?

Aku bisa tambahkan:

·       Tracking open/click (SendGrid/Mailgun)
·       Personalisasi nama dari CSV
·       Auto‑retry hanya untuk error tertentu (misalnya timeout)
·       Dashboard HTML untuk monitoring
·       Mode “slow send” (1 email per jam)