Python ile E-posta Bildirimi Gönderme: smtplib Kullanımı

Sistem yöneticiliğinde en sık ihtiyaç duyulan şeylerden biri otomatik bildirimlerdir. Disk doldu mu? Servis çöktü mü? Yedekleme tamamlandı mı? Tüm bu olaylar için e-posta bildirimi göndermek, gece 3’te telefon almak yerine sabah kahvenizi içerken durumu değerlendirmenizi sağlar. Python’un smtplib modülü, bu bildirimleri script’lerinize entegre etmek için oldukça güçlü ve esnek bir araçtır.

smtplib Nedir ve Neden Kullanmalıyız?

Python standart kütüphanesinin bir parçası olan smtplib, SMTP (Simple Mail Transfer Protocol) üzerinden e-posta göndermenizi sağlar. Ekstra kurulum gerektirmez, her Python ortamında hazır gelir. mail veya sendmail komutlarına göre çok daha fazla kontrol imkanı sunar: HTML içerik, ek dosya, birden fazla alıcı, kimlik doğrulama, TLS/SSL desteği gibi her şeyi Python kodu içinde yönetebilirsiniz.

Özellikle şu senaryolarda smtplib tercih nedeni olur:

  • Taşınabilirlik: Script’iniz farklı sunucularda çalışacaksa sistem mail komutu olmayabilir ama Python neredeyse her yerde vardır
  • Zengin içerik: HTML formatında, ek dosyalı, özel başlıklı mailler göndermek gerektiğinde
  • Kontrol: Her adımı kod içinde yönetmek, hata yakalama ve loglama yapmak istediğinizde
  • Entegrasyon: Monitoring script’leri, cron job’lar, CI/CD pipeline’larına gömülü bildirim sistemi kurarken

Temel Kurulum ve İlk Mail

Önce en basit haliyle bir mail gönderelim. Gmail SMTP’yi kullanacağız çünkü büyük ihtimalle her sysadmin’in erişimi vardır. Ancak kurumsal ortamlarda kendi SMTP sunucunuzu kullanmanız daha mantıklı olacaktır.

python3 << 'EOF'
import smtplib
from email.mime.text import MIMEText

# Basit metin maili
gonderen = "[email protected]"
alici = "[email protected]"
konu = "Test Bildirimi"
icerik = "Bu bir test mesajidir. Sistem calisiyor."

msg = MIMEText(icerik)
msg['Subject'] = konu
msg['From'] = gonderen
msg['To'] = alici

# SMTP sunucusuna baglan ve gonder
with smtplib.SMTP('smtp.gmail.com', 587) as sunucu:
    sunucu.starttls()
    sunucu.login('[email protected]', 'uygulama-sifresi')
    sunucu.send_message(msg)
    print("Mail basariyla gonderildi!")
EOF

Gmail kullanıyorsanız dikkat etmeniz gereken önemli bir nokta var: 2023 itibarıyla Google, normal hesap şifresiyle SMTP girişini kapatmıştır. Bunun yerine “App Password” (Uygulama Şifresi) oluşturmanız gerekir. Google hesabınızın güvenlik ayarlarından 2 faktörlü doğrulamayı aktif edip ardından uygulama şifresi oluşturabilirsiniz.

Yapılandırma Dosyasından Ayarları Okuma

Şifreleri script içine gömmek kötü bir pratiktir. Özellikle Git reposuna yüklenecek script’lerde bu hatayı görmek çok yaygın ama çok tehlikelidir. Ayarları ayrı bir yapılandırma dosyasında tutun:

# /etc/sysadmin/mail_config.ini dosyasi olustur
cat > /etc/sysadmin/mail_config.ini << 'EOF'
[smtp]
sunucu = smtp.sirket.com
port = 587
kullanici = [email protected]
sifre = gizli-sifre-buraya
tls = true

[bildirim]
gonderen = [email protected]
varsayilan_alici = [email protected]
acil_alici = [email protected]
EOF

# Dosya iznini kisitla
chmod 640 /etc/sysadmin/mail_config.ini
chown root:sysadmin /etc/sysadmin/mail_config.ini
python3 << 'EOF'
import smtplib
import configparser
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

def mail_ayarlarini_yukle(config_dosyasi='/etc/sysadmin/mail_config.ini'):
    config = configparser.ConfigParser()
    config.read(config_dosyasi)
    return config

def basit_mail_gonder(konu, icerik, alici=None):
    config = mail_ayarlarini_yukle()
    
    smtp_sunucu = config['smtp']['sunucu']
    smtp_port = int(config['smtp']['port'])
    kullanici = config['smtp']['kullanici']
    sifre = config['smtp']['sifre']
    gonderen = config['bildirim']['gonderen']
    
    if alici is None:
        alici = config['bildirim']['varsayilan_alici']
    
    msg = MIMEText(icerik, 'plain', 'utf-8')
    msg['Subject'] = konu
    msg['From'] = gonderen
    msg['To'] = alici
    
    with smtplib.SMTP(smtp_sunucu, smtp_port) as sunucu:
        sunucu.starttls()
        sunucu.login(kullanici, sifre)
        sunucu.send_message(msg)
    
    print(f"Mail gonderildi: {alici}")

# Test
basit_mail_gonder("Sistem Durumu", "Tum servisler normal calisiyor.")
EOF

HTML Formatında Bildirim Gönderme

Düz metin mailler okunabilir ama kritik bilgileri vurgulamak için HTML formatı çok daha etkilidir. Disk kullanımı, servis durumu gibi bilgileri renkli ve yapılandırılmış şekilde iletebilirsiniz:

python3 << 'EOF'
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from datetime import datetime
import socket

def html_bildirim_gonder(konu, baslik, mesaj, durum="bilgi", alici="[email protected]"):
    
    # Durum rengini belirle
    renk_haritasi = {
        "bilgi": "#3498db",
        "basari": "#27ae60", 
        "uyari": "#f39c12",
        "kritik": "#e74c3c"
    }
    renk = renk_haritasi.get(durum, "#3498db")
    sunucu_adi = socket.gethostname()
    zaman = datetime.now().strftime("%d.%m.%Y %H:%M:%S")
    
    html_icerik = f"""
    <html>
    <body style="font-family: Arial, sans-serif; margin: 0; padding: 20px; background: #f5f5f5;">
        <div style="max-width: 600px; margin: 0 auto; background: white; border-radius: 8px; overflow: hidden; box-shadow: 0 2px 10px rgba(0,0,0,0.1);">
            <div style="background: {renk}; color: white; padding: 20px;">
                <h2 style="margin: 0;">{baslik}</h2>
                <p style="margin: 5px 0 0 0; opacity: 0.8;">Sunucu: {sunucu_adi}</p>
            </div>
            <div style="padding: 25px;">
                <p style="color: #333; line-height: 1.6;">{mesaj}</p>
                <hr style="border: none; border-top: 1px solid #eee; margin: 20px 0;">
                <p style="color: #999; font-size: 12px;">Gonderim zamani: {zaman}</p>
            </div>
        </div>
    </body>
    </html>
    """
    
    msg = MIMEMultipart('alternative')
    msg['Subject'] = konu
    msg['From'] = "[email protected]"
    msg['To'] = alici
    
    # Hem plain text hem HTML ekle (mail istemcisi desteklemiyorsa plain text goruntulenir)
    plain_text = MIMEText(f"{baslik}nn{mesaj}nnZaman: {zaman}", 'plain', 'utf-8')
    html_part = MIMEText(html_icerik, 'html', 'utf-8')
    
    msg.attach(plain_text)
    msg.attach(html_part)
    
    with smtplib.SMTP('smtp.sirket.com', 587) as sunucu:
        sunucu.starttls()
        sunucu.login('[email protected]', 'sifre')
        sunucu.send_message(msg)

# Kullanim ornekleri
html_bildirim_gonder(
    "KRITIK: Disk Dolmak Uzere",
    "Disk Kullanimi Alarm Seviyesinde",
    "/var/log dizini %92 dolu. Hemen mudahale gerekiyor!",
    durum="kritik"
)
EOF

Log Dosyası Ekleyerek Bildirim Gönderme

Servis çöktüğünde sadece “servis çöktü” yazmak yetmez. İlgili log satırlarını da eklemek, problemi mail’i okurken anlamamızı kolaylaştırır:

python3 << 'EOF'
import smtplib
import os
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
from datetime import datetime

def log_ekli_mail_gonder(konu, mesaj, log_dosyasi=None, alici="[email protected]"):
    
    msg = MIMEMultipart()
    msg['Subject'] = konu
    msg['From'] = "[email protected]"
    msg['To'] = alici
    
    # Mail icerigi
    zaman = datetime.now().strftime("%d.%m.%Y %H:%M:%S")
    tam_mesaj = f"{mesaj}nnBildirim zamani: {zaman}"
    msg.attach(MIMEText(tam_mesaj, 'plain', 'utf-8'))
    
    # Log dosyasini ek olarak ekle
    if log_dosyasi and os.path.exists(log_dosyasi):
        with open(log_dosyasi, 'rb') as f:
            ek = MIMEBase('application', 'octet-stream')
            ek.set_payload(f.read())
        
        encoders.encode_base64(ek)
        dosya_adi = os.path.basename(log_dosyasi)
        ek.add_header('Content-Disposition', f'attachment; filename="{dosya_adi}"')
        msg.attach(ek)
        print(f"Log dosyasi eklendi: {log_dosyasi}")
    
    with smtplib.SMTP('smtp.sirket.com', 587) as sunucu:
        sunucu.starttls()
        sunucu.login('[email protected]', 'sifre')
        sunucu.send_message(msg)
    
    print(f"Mail gonderildi: {alici}")

# Nginx hata logunun son 100 satirini gecici dosyaya kaydet, sonra gonder
import subprocess

with open('/tmp/nginx_son_hatalar.txt', 'w') as f:
    subprocess.run(['tail', '-100', '/var/log/nginx/error.log'], 
                   stdout=f, stderr=subprocess.DEVNULL)

log_ekli_mail_gonder(
    "Nginx Hata Raporu",
    "Nginx servisinde hatalar tespit edildi. Detaylar ekte.",
    log_dosyasi='/tmp/nginx_son_hatalar.txt'
)
EOF

Gerçek Dünya Senaryosu: Disk Kullanım Monitörü

Teoriden pratiğe geçelim. Gerçek bir sysadmin script’i yazalım: Disk kullanımını kontrol eden, belirlenen eşiği aşınca mail atan, her gün özet rapor gönderen bir sistem.

cat > /usr/local/bin/disk_monitor.py << 'EOF'
#!/usr/bin/env python3
"""
Disk Kullanim Monitoru
Kritik esigi asinirsa aninda bildirim, gunluk ozet raporunu da gonderir.
"""

import smtplib
import shutil
import subprocess
import socket
import logging
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from datetime import datetime

# Yapilandirma
SMTP_SUNUCU = "smtp.sirket.com"
SMTP_PORT = 587
SMTP_KULLANICI = "[email protected]"
SMTP_SIFRE = "gizli-sifre"
GONDEREN = "[email protected]"
ALICI_LIST = ["[email protected]", "[email protected]"]
ACIL_ALICI = "[email protected]"
UYARI_ESIGI = 80    # %80 dolunca uyari
KRITIK_ESIGI = 90   # %90 dolunca kritik alarm

# Loglama
logging.basicConfig(
    filename='/var/log/disk_monitor.log',
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)

def disk_kullanimi_al():
    """Tum mount noktalari icin disk kullanim bilgisini don."""
    sonuclar = []
    
    result = subprocess.run(
        ['df', '-h', '--output=target,pcent,used,avail'],
        capture_output=True, text=True
    )
    
    satirlar = result.stdout.strip().split('n')[1:]  # Baslik satiri atlandi
    for satir in satirlar:
        parcalar = satir.split()
        if len(parcalar) >= 4:
            mount = parcalar[0]
            yuzde = int(parcalar[1].replace('%', ''))
            kullanilan = parcalar[2]
            bos = parcalar[3]
            sonuclar.append({
                'mount': mount,
                'yuzde': yuzde,
                'kullanilan': kullanilan,
                'bos': bos
            })
    
    return sonuclar

def mail_gonder(konu, icerik, alicilar, html=False):
    """SMTP uzerinden mail gonder."""
    try:
        msg = MIMEMultipart('alternative')
        msg['Subject'] = konu
        msg['From'] = GONDEREN
        msg['To'] = ', '.join(alicilar)
        
        tip = 'html' if html else 'plain'
        msg.attach(MIMEText(icerik, tip, 'utf-8'))
        
        with smtplib.SMTP(SMTP_SUNUCU, SMTP_PORT) as sunucu:
            sunucu.starttls()
            sunucu.login(SMTP_KULLANICI, SMTP_SIFRE)
            sunucu.sendmail(GONDEREN, alicilar, msg.as_string())
        
        logging.info(f"Mail gonderildi: {konu} -> {alicilar}")
        return True
        
    except Exception as e:
        logging.error(f"Mail gonderilemedi: {e}")
        return False

def disk_kontrol_et():
    """Disk kullanimi kontrol et, gerekirse alarm gonder."""
    sunucu_adi = socket.gethostname()
    diskler = disk_kullanimi_al()
    
    kritik_diskler = []
    uyari_diskleri = []
    
    for disk in diskler:
        if disk['yuzde'] >= KRITIK_ESIGI:
            kritik_diskler.append(disk)
        elif disk['yuzde'] >= UYARI_ESIGI:
            uyari_diskleri.append(disk)
    
    # Kritik durumlar icin aninda bildirim
    if kritik_diskler:
        icerik = f"KRITIK DISK ALARMI - {sunucu_adi}n"
        icerik += f"Tarih: {datetime.now().strftime('%d.%m.%Y %H:%M:%S')}nn"
        icerik += "Kritik Seviyede Dolu Diskler:n"
        icerik += "-" * 40 + "n"
        
        for disk in kritik_diskler:
            icerik += f"Mount: {disk['mount']}n"
            icerik += f"Kullanim: %{disk['yuzde']}n"
            icerik += f"Kullanilan: {disk['kullanilan']}, Bos: {disk['bos']}nn"
        
        alicilar = ALICI_LIST + [ACIL_ALICI]
        mail_gonder(
            f"[KRITIK] {sunucu_adi} - Disk Dolmak Uzere",
            icerik,
            alicilar
        )
    
    # Uyari durumlar
    if uyari_diskleri:
        icerik = f"Disk Uyarisi - {sunucu_adi}nn"
        for disk in uyari_diskleri:
            icerik += f"{disk['mount']}: %{disk['yuzde']} dolu ({disk['bos']} bos)n"
        
        mail_gonder(
            f"[UYARI] {sunucu_adi} - Disk Kullanimi Yuksek",
            icerik,
            ALICI_LIST
        )

def gunluk_rapor_gonder():
    """Tum disklerin gunluk ozet raporunu gonder."""
    sunucu_adi = socket.gethostname()
    diskler = disk_kullanimi_al()
    
    icerik = f"Gunluk Disk Raporu - {sunucu_adi}n"
    icerik += f"Tarih: {datetime.now().strftime('%d.%m.%Y')}nn"
    
    for disk in diskler:
        durum = "OK"
        if disk['yuzde'] >= KRITIK_ESIGI:
            durum = "KRITIK"
        elif disk['yuzde'] >= UYARI_ESIGI:
            durum = "UYARI"
        
        icerik += f"[{durum}] {disk['mount']}: %{disk['yuzde']} "
        icerik += f"({disk['kullanilan']} kullanilan, {disk['bos']} bos)n"
    
    mail_gonder(
        f"Gunluk Disk Raporu - {sunucu_adi}",
        icerik,
        ALICI_LIST
    )

if __name__ == "__main__":
    import sys
    
    if len(sys.argv) > 1 and sys.argv[1] == '--rapor':
        gunluk_rapor_gonder()
    else:
        disk_kontrol_et()
EOF

chmod +x /usr/local/bin/disk_monitor.py

Cron job’larını da ayarlayalım:

# Her 15 dakikada disk kontrol, sabah 8'de gunluk rapor
cat >> /etc/cron.d/disk-monitor << 'EOF'
*/15 * * * * root /usr/local/bin/disk_monitor.py 2>/dev/null
0 8 * * * root /usr/local/bin/disk_monitor.py --rapor 2>/dev/null
EOF

Hata Yakalama ve Yeniden Deneme Mekanizması

Üretim ortamında SMTP sunucusu geçici olarak ulaşılamaz olabilir. Bu durumda bildirimin kaybolmaması için bir retry mekanizması eklemek iyi bir pratiktir:

python3 << 'EOF'
import smtplib
import time
import logging
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

def mail_gonder_retry(konu, icerik, alici, max_deneme=3, bekleme_suresi=30):
    """
    Mail gonderimini dener, basarisiz olursa belirtilen sure bekleyip tekrar dener.
    max_deneme: Maksimum deneme sayisi
    bekleme_suresi: Denemeler arasi saniye
    """
    
    msg = MIMEText(icerik, 'plain', 'utf-8')
    msg['Subject'] = konu
    msg['From'] = "[email protected]"
    msg['To'] = alici
    
    son_hata = None
    
    for deneme in range(1, max_deneme + 1):
        try:
            with smtplib.SMTP('smtp.sirket.com', 587, timeout=10) as sunucu:
                sunucu.starttls()
                sunucu.login('[email protected]', 'sifre')
                sunucu.send_message(msg)
            
            logging.info(f"Mail gonderildi ({deneme}. denemede): {konu}")
            return True
            
        except smtplib.SMTPAuthenticationError as e:
            # Kimlik dogrulama hatasi - yeniden denemenin anlami yok
            logging.error(f"SMTP kimlik dogrulama hatasi: {e}")
            raise
            
        except smtplib.SMTPException as e:
            son_hata = e
            logging.warning(f"Mail gonderilemedi ({deneme}/{max_deneme}): {e}")
            
            if deneme < max_deneme:
                logging.info(f"{bekleme_suresi} saniye sonra tekrar deneniyor...")
                time.sleep(bekleme_suresi)
                
        except Exception as e:
            son_hata = e
            logging.error(f"Beklenmedik hata ({deneme}/{max_deneme}): {e}")
            
            if deneme < max_deneme:
                time.sleep(bekleme_suresi)
    
    logging.error(f"Mail gonderilemedi, tum denemeler bitti. Son hata: {son_hata}")
    return False

# Kullanim
basari = mail_gonder_retry(
    "Kritik Alarm",
    "Veritabani baglantisi koptu!",
    "[email protected]",
    max_deneme=3,
    bekleme_suresi=60
)

if not basari:
    # Son care: sistem log'una yaz
    logging.critical("Mail bildirimi GONDERILEMEDI! Manuel kontrol gerekiyor.")
EOF

SSL ile Dogrudan Baglanma

Bazı SMTP sunucuları 465 portunda doğrudan SSL bağlantısı ister. 587/STARTTLS yerine bu durumda SMTP_SSL kullanmalısınız:

python3 << 'EOF'
import smtplib
import ssl
from email.mime.text import MIMEText

def ssl_mail_gonder(konu, icerik, alici):
    """
    Port 465 ile dogrudan SSL baglantisi kullanir.
    STARTTLS (587) yerine bunu tercih eden SMTP sunuculari icin.
    """
    
    # Guvenceli SSL context olustur
    ssl_context = ssl.create_default_context()
    
    msg = MIMEText(icerik, 'plain', 'utf-8')
    msg['Subject'] = konu
    msg['From'] = "[email protected]"
    msg['To'] = alici
    
    # SMTP_SSL ile direk sifreli kanal ac
    with smtplib.SMTP_SSL('smtp.sirket.com', 465, context=ssl_context) as sunucu:
        sunucu.login('[email protected]', 'sifre')
        sunucu.send_message(msg)
    
    print("SSL ile mail gonderildi.")

# Dahili sunucu icin SSL dogrulama devre disi (YALNIZCA test ortami!)
def dahili_sunucu_mail(konu, icerik, alici):
    """
    Oz-imzali sertifika kullanan ic SMTP sunuculari icin.
    Uretimde kullanimdan kacinin, sertifika dogrulamayi devre disi birakir.
    """
    ssl_context = ssl.create_default_context()
    ssl_context.check_hostname = False
    ssl_context.verify_mode = ssl.CERT_NONE
    
    msg = MIMEText(icerik, 'plain', 'utf-8')
    msg['Subject'] = konu
    msg['From'] = "[email protected]"
    msg['To'] = alici
    
    with smtplib.SMTP_SSL('smtp-ic.sirket.local', 465, context=ssl_context) as sunucu:
        sunucu.login('[email protected]', 'sifre')
        sunucu.send_message(msg)

ssl_mail_gonder("Sistem Alami", "Kritik servis durdu!", "[email protected]")
EOF

Birden Fazla Alıcıya Toplu Gönderim

Farklı alarm seviyelerine göre farklı kişilere mail atmak yaygın bir ihtiyaçtır. Aşağıdaki örnek bunu temiz bir şekilde yönetir:

python3 << 'EOF'
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

# Alici gruplari
ALICI_GRUPLARI = {
    "sysadmin": ["[email protected]", "[email protected]"],
    "dba": ["[email protected]"],
    "gelistirici": ["[email protected]"],
    "yonetim": ["[email protected]", "[email protected]"],
    "oncall": ["[email protected]"]
}

def grup_maili_gonder(konu, icerik, gruplar, cc_gruplari=None):
    """
    Belirtilen gruplara mail gonder, opsiyonel CC grubu destekler.
    gruplar: ['sysadmin', 'dba'] gibi grup listesi
    cc_gruplari: CC'ye eklenecek gruplar
    """
    
    tum_alicilar = []
    cc_alicilar = []
    
    for grup in gruplar:
        if grup in ALICI_GRUPLARI:
            tum_alicilar.extend(ALICI_GRUPLARI[grup])
    
    if cc_gruplari:
        for grup in cc_gruplari:
            if grup in ALICI_GRUPLARI:
                cc_alicilar.extend(ALICI_GRUPLARI[grup])
    
    if not tum_alicilar:
        print("Hic alici bulunamadi!")
        return False
    
    msg = MIMEMultipart()
    msg['Subject'] = konu
    msg['From'] = "[email protected]"
    msg['To'] = ', '.join(tum_alicilar)
    
    if cc_alicilar:
        msg['Cc'] = ', '.join(cc_alicilar)
    
    msg.attach(MIMEText(icerik, 'plain', 'utf-8'))
    
    tum_gorecekler = tum_alicilar + cc_alicilar
    
    with smtplib.SMTP('smtp.sirket.com', 587) as sunucu:
        sunucu.starttls()
        sunucu.login('[email protected]', 'sifre')
        sunucu.sendmail('[email protected]', tum_gorecekler, msg.as_string())
    
    print(f"Mail gonderildi. Alicilar: {tum_gorecekler}")
    return True

# Veritabani alarm senaryosu
grup_maili_gonder(
    "[KRITIK] Uretim DB Yavas Sorgu Alarmi",
    "Son 10 dakikada 50'den fazla yavas sorgu tespit edildi. Detaylar icin DB monitoring panelini kontrol edin.",
    gruplar=["dba", "oncall"],
    cc_gruplari=["yonetim"]
)
EOF

Ortam Degiskenlerinden Konfigürasyon Okuma

Containerized ortamlarda (Docker, Kubernetes) konfigürasyonu ortam değişkenlerinden okumak daha uygun bir yaklaşımdır:

# Docker veya systemd service icin ortam degiskenleri
export SMTP_SUNUCU="smtp.sirket.com"
export SMTP_PORT="587"
export SMTP_KULLANICI="[email protected]"
export SMTP_SIFRE="gizli-sifre"
export BILDIRIM_ALICI="[email protected]"

python3 << 'EOF'
import smtplib
import os
from email.mime.text import MIMEText

def env_mail_gonder(konu, icerik):
    """
    Tum SMTP ayarlarini ortam degiskenlerinden okur.
    12-factor app prensibine uygun yaklasim.
    """
    
    smtp_sunucu = os.environ.get('SMTP_SUNUCU')
    smtp_port = int(os.environ.get('SMTP_PORT', '587'))
    kullanici = os.environ.get('SMTP_KULLANICI')
    sifre = os.environ.get('SMTP_SIFRE')
    alici = os.environ.get('BILDIRIM_ALICI')
    
    # Zorunlu degiskenleri kontrol et
    eksik = []
    for degisken in ['SMTP_SUNUCU', 'SMTP_KULLANICI', 'SMTP_SIFRE', 'BILDIRIM_ALICI']:
        if not os.environ.get(degisken):
            eksik.append(degisken)
    
    if eksik:
        raise EnvironmentError(f"Eksik ortam degiskenleri: {', '.join(eksik)}")
    
    msg = MIMEText(icerik, 'plain', 'utf-8')
    msg['Subject'] = konu
    msg['From'] = kullanici
    msg['To'] = alici
    
    with smtplib.SMTP(smtp_sunucu, smtp_port) as sunucu:
        sunucu.starttls()
        sunucu.login(kullanici, sifre)
        sunucu.send_message(msg)
    
    print(f"Mail gonderildi: {alici}")

env_mail_gonder("Konteyner Bildirimi", "Uygulama baslatildi ve hazir.")
EOF

Güvenlik Notları

Bu konuda pratik birkaç hatırlatma yapmadan geçmek olmaz:

  • Sifreleri asla kod icine gommeyin: Mutlaka config dosyasi, ortam degiskeni veya secrets manager kullanin
  • Config dosyasi izinleri: SMTP sifresini iceren dosyalari chmod 600 veya chmod 640 ile koruyun
  • App Password kullanin: Gmail gibi servislerde ana hesap sifrenizi kullanmayin, servis odakli uygulama sifresi olusturun
  • TLS zorunlu tutun: starttls() cagrisini atlamayin, sifrelenmemis baglantida kimlik bilgileriniz acikta kalir
  • Rate limiting: Cok sik mail gonderimi hem SMTP sunucunuzda kara listeye girmenize hem de alicilarinizin sizi spam olarak isaretle memesine neden olabilir. Bildirimleri gruplandirin
  • Mail flooding’e dikkat: Bir alarm durumu surekli tetiklenirse binlerce mail gidebilir. Cooldown mekanizmasi ekleyin: son gonderim zamanini bir dosyaya yazin, uzerinden N dakika gecmemisse tekrar gondermeyin

Sonuç

smtplib, Python ekosisteminde e-posta otomasyonu için oldukça yeterli ve sağlam bir araçtır. Basit servis durum bildirimlerinden HTML formatında zengin raporlara, log eki gönderiminden grup bazlı alarm sistemine kadar geniş bir yelpazeyi karşılar. Dışarıdan bağımlılık gerektirmediği için cron job’lardan container’lara kadar her ortamda güvenle kullanılabilir.

Burada yazdığınız bildirim sistemini zamanla geliştirmek isterseniz şu adımları düşünebilirsiniz: Bildirimleri veritabanına kaydetmek, cooldown sürelerini yönetmek için Redis kullanmak, alarm özetlerini düzenli zaman dilimlerinde gruplandırmak. Ama en basit hali bile, gece yarısı telefon beklemek yerine sabah mailboxınızı kontrol etmenizi sağlayacaktır. Bu da başlı başına büyük bir kazanım.

Yorum yapın