""" Notifier - Email and Webhook Notifications Handles Mailgun emails and outgoing webhooks Compatible with Python 3.6+ """ import requests import logging from jinja2 import Template logger = logging.getLogger('Notifier') class Notifier: def __init__(self, config): self.config = config self.enabled = config['notifications']['enabled'] self.mailgun_api_key = config['notifications']['mailgun']['api_key'] self.mailgun_domain = config['notifications']['mailgun']['domain'] self.recipients = config['notifications']['recipients'] self.webhook_config = config.get('webhooks', {}) def send_email(self, template_name, recipients, data): """ Send email via Mailgun Args: template_name: Name of email template recipients: List of email addresses data: Template data dict """ if not self.enabled: logger.info("Notifications disabled, skipping email") return try: # Simple templates (full template system would load from YAML) templates = { 'a1_to_a2_complete': { 'subject': "✅ Master Assets Downloaded - Campaign {campaign_name}", 'html': """

Master Assets Downloaded Successfully

Campaign: {campaign_name} ({campaign_id})

Campaign Number: {campaign_number}

Assets Downloaded: {asset_count}

Status Updated: A1 → A2


All assets have been downloaded and uploaded to Box with tracking IDs.

""" }, 'a2_to_a3_complete': { 'subject': "✅ Localized Assets Uploaded - Campaign {campaign_name}", 'html': """

Localized Assets Uploaded Successfully

Campaign: {campaign_name}

Campaign ID: {campaign_id}

Assets Uploaded: {asset_count}

Status Updated: A2 → A3


All localized assets have been uploaded to DAM.

""" }, 'upload_failed': { 'subject': "❌ Upload Failed - {filename}", 'html': """

Upload Failed

Filename: {filename}

Tracking ID: {tracking_id}

Error: {error}


Please investigate the error.

""" }, 'a1_to_a2_partial': { 'subject': "⚠️ Partial Download - Campaign {campaign_name}", 'html': """

Campaign Partially Processed

Campaign: {campaign_name} ({campaign_id})

Total Assets: {total_assets}

Successful: {successful}

Failed: {failed}


Status NOT updated. Campaign remains at A1.

Please review failed assets and retry.

""" } } template_config = templates.get(template_name, { 'subject': 'Ferrero Automation Notification', 'html': '

{}

'.format(data) }) # Render subject and body subject = template_config['subject'].format(**data) html_template = Template(template_config['html']) html_body = html_template.render(**data) # Send via Mailgun response = requests.post( "https://api.mailgun.net/v3/{}/messages".format(self.mailgun_domain), auth=("api", self.mailgun_api_key), data={ "from": "Ferrero Automation ".format(self.mailgun_domain), "to": recipients if isinstance(recipients, list) else [recipients], "subject": subject, "html": html_body }, timeout=10 ) if response.status_code == 200: logger.info("Email sent: {} to {}".format(template_name, recipients)) else: logger.error("Email failed: HTTP {} - {}".format( response.status_code, response.text )) except Exception as e: logger.error("Email error: {}".format(str(e))) def send_webhook(self, url, payload): """ Send outgoing webhook notification Args: url: Webhook URL payload: dict to send as JSON Returns: bool: Success status """ try: # Get webhook config if exists webhook_config = None for name, config in self.webhook_config.items(): if config.get('url') == url: webhook_config = config break if not webhook_config: webhook_config = {'timeout_seconds': 10, 'auth': {}} # Prepare headers headers = {'Content-Type': 'application/json'} # Add auth if configured auth_config = webhook_config.get('auth', {}) if auth_config.get('type') == 'bearer' and auth_config.get('token'): headers['Authorization'] = 'Bearer {}'.format(auth_config['token']) # Send webhook response = requests.post( url, json=payload, headers=headers, timeout=webhook_config.get('timeout_seconds', 10) ) if response.status_code in [200, 201, 202]: logger.info("Webhook sent successfully: {}".format(url)) return True else: logger.warning("Webhook failed: HTTP {} - {}".format( response.status_code, response.text[:200] )) return False except Exception as e: logger.error("Webhook error: {}".format(str(e))) return False