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
mailkomutu 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 600veyachmod 640ile 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.