Files
wevads-platform/scripts/smart-sender.py
2026-02-26 04:53:11 +01:00

250 lines
7.3 KiB
Python
Executable File

#!/usr/bin/env python3
"""
SMART SENDER
Envoi intelligent avec:
- Warmup automatique
- Volume optimization
- Sélection méthode optimale
- Rotation IPs/domaines
"""
import psycopg2
import subprocess
import sys
import json
from datetime import datetime
DB_CONFIG = {
'host': 'localhost',
'database': 'adx_system',
'user': 'admin',
'password': 'admin123'
}
# Import warmup manager functions
sys.path.append('/opt/wevads/scripts')
from importlib import import_module
def get_db():
return psycopg2.connect(**DB_CONFIG)
def get_best_method_for_target(target_isp, required_volume=100):
"""
Select best sending method based on:
- Volume capacity (can handle required_volume)
- Inbox rate
- Volume quality score
"""
conn = get_db()
cur = conn.cursor()
# Get methods with available capacity
cur.execute("""
SELECT
w.sending_method,
w.ip_address,
w.domain,
w.current_daily_limit,
w.current_inbox_rate,
w.volume_score,
w.status,
w.warmup_stage,
w.id as warmup_id
FROM admin.warmup_tracking w
WHERE w.status NOT IN ('burned', 'throttled')
AND w.current_daily_limit >= %s
ORDER BY w.volume_score DESC NULLS LAST
LIMIT 10
""", (required_volume,))
methods = cur.fetchall()
conn.close()
if not methods:
return None
# Return best option
best = methods[0]
return {
'method': best[0],
'ip': str(best[1]),
'domain': best[2],
'daily_limit': best[3],
'inbox_rate': best[4],
'volume_score': best[5],
'status': best[6],
'stage': best[7],
'warmup_id': best[8]
}
def get_available_senders(target_isp=None, min_volume=50):
"""Get all available senders sorted by score"""
conn = get_db()
cur = conn.cursor()
cur.execute("""
SELECT
w.id,
w.sending_method,
w.ip_address,
w.domain,
w.current_daily_limit - COALESCE(
(SELECT SUM(emails_sent) FROM admin.volume_history
WHERE warmup_id = w.id AND hour_timestamp >= CURRENT_DATE), 0
) as remaining_today,
w.current_inbox_rate,
w.volume_score,
w.warmup_stage,
dc.target_isps
FROM admin.warmup_tracking w
LEFT JOIN admin.discovered_combos dc ON w.combo_id = dc.id
WHERE w.status NOT IN ('burned', 'throttled')
AND w.current_daily_limit >= %s
ORDER BY w.volume_score DESC NULLS LAST
""", (min_volume,))
senders = []
for row in cur.fetchall():
wid, method, ip, domain, remaining, inbox, score, stage, targets = row
# Filter by target ISP if specified
if target_isp and targets:
if target_isp not in targets and '*' not in targets:
continue
senders.append({
'warmup_id': wid,
'method': method,
'ip': str(ip) if ip else None,
'domain': domain,
'remaining_today': remaining or 0,
'inbox_rate': inbox,
'volume_score': score,
'stage': stage,
'targets': targets
})
conn.close()
return senders
def send_with_warmup(to_emails, target_isp, subject, body, method=None):
"""
Send emails with automatic warmup management
- Selects best method if not specified
- Respects daily limits
- Records stats for warmup progression
"""
volume_needed = len(to_emails)
# Get available senders
senders = get_available_senders(target_isp, min_volume=10)
if not senders:
print("❌ No available senders")
return {'success': False, 'reason': 'No senders available'}
print(f"\n📧 Sending {volume_needed} emails to {target_isp}")
print(f" Available senders: {len(senders)}")
# Distribute across senders
emails_sent = 0
results = []
for sender in senders:
if emails_sent >= volume_needed:
break
batch_size = min(sender['remaining_today'], volume_needed - emails_sent)
if batch_size <= 0:
continue
print(f"\n Using {sender['method']} via {sender['domain'] or sender['ip']}")
print(f" Batch: {batch_size} (remaining: {sender['remaining_today']})")
# Get emails for this batch
batch_emails = to_emails[emails_sent:emails_sent + batch_size]
# Send batch (placeholder - actual send logic)
# In production, call the appropriate sender
batch_result = {
'sent': len(batch_emails),
'inbox': int(len(batch_emails) * 0.8), # Simulated
'spam': int(len(batch_emails) * 0.1),
'bounced': int(len(batch_emails) * 0.1)
}
# Record in warmup
subprocess.run([
'python3', '/opt/wevads/scripts/warmup-manager.py', 'record',
sender['ip'] or '127.0.0.1',
sender['method'],
str(batch_result['sent']),
str(batch_result['inbox']),
str(batch_result['spam'])
], capture_output=True)
emails_sent += batch_result['sent']
results.append({
'sender': sender,
'result': batch_result
})
return {
'success': True,
'total_sent': emails_sent,
'batches': results
}
def show_sender_status():
"""Show available senders and their capacity"""
print("=" * 80)
print("📧 AVAILABLE SENDERS")
print("=" * 80)
senders = get_available_senders()
print(f"\n{'Method':<12} {'Domain/IP':<25} {'Remaining':>10} {'Inbox%':>8} {'Score':>8} {'Stage'}")
print("-" * 80)
total_capacity = 0
for s in senders:
identifier = s['domain'] or s['ip'] or 'N/A'
stage_icons = {1: '🔵', 2: '🟡', 3: '🟢', 4: '🔥'}
stage_icon = stage_icons.get(s['stage'], '')
print(f"{s['method']:<12} {identifier[:25]:<25} {s['remaining_today']:>10} {s['inbox_rate'] or 0:>7.1f}% {s['volume_score'] or 0:>8.1f} {stage_icon}")
total_capacity += s['remaining_today']
print("-" * 80)
print(f"Total capacity today: {total_capacity:,} emails")
def main():
if len(sys.argv) < 2:
show_sender_status()
return
cmd = sys.argv[1]
if cmd == 'status':
show_sender_status()
elif cmd == 'best':
target = sys.argv[2] if len(sys.argv) > 2 else 'hotmail'
volume = int(sys.argv[3]) if len(sys.argv) > 3 else 100
best = get_best_method_for_target(target, volume)
if best:
print(f"\n🎯 Best sender for {target} ({volume} emails):")
print(f" Method: {best['method']}")
print(f" Domain: {best['domain']}")
print(f" IP: {best['ip']}")
print(f" Daily Limit: {best['daily_limit']}")
print(f" Inbox Rate: {best['inbox_rate']}%")
print(f" Score: {best['volume_score']}")
else:
print(f"❌ No suitable sender for {volume} emails")
else:
print("Commands: status, best")
if __name__ == '__main__':
main()