| from sendgrid import SendGridAPIClient |
| from sendgrid.helpers.mail import Mail |
| from strands import tool |
| from config.settings import settings |
| from typing import Dict, Union |
| import logging |
|
|
| logger = logging.getLogger(__name__) |
|
|
| @tool( |
| name="send_notification_email", |
| description="Sends HTML email notifications about Topcoder challenges to registered users" |
| ) |
| def send_email(to: str, html_content: str, subject: str) -> Dict[str, Union[str, list]]: |
| """Send an email notification about relevant Topcoder challenges using SendGrid. |
| |
| This tool handles the complete email delivery process including validation, |
| formatting, and error handling. It uses the configured SendGrid API to send |
| HTML-formatted challenge notifications to registered users. |
| |
| Args: |
| to: The recipient's email address (must be a valid email format) |
| html_content: The HTML-formatted content of the email notification |
| subject: The subject line for the email notification |
| |
| Returns: |
| Dictionary with status and content indicating success or failure details |
| """ |
| |
| logger.info(f"Attempting to send email to {to} with subject: '{subject}'") |
| |
| |
| if not settings.SENDGRID_API_KEY: |
| error_msg = "SENDGRID_API_KEY environment variable is not set. Please configure SendGrid API key." |
| logger.error(error_msg) |
| return { |
| "status": "error", |
| "content": [ |
| {"text": error_msg} |
| ] |
| } |
| |
| if not settings.SENDGRID_FROM_EMAIL: |
| error_msg = "SENDGRID_FROM_EMAIL is not configured. Please set the sender email address." |
| logger.error(error_msg) |
| return { |
| "status": "error", |
| "content": [ |
| {"text": error_msg} |
| ] |
| } |
| |
| |
| if not to or "@" not in to: |
| error_msg = f"Invalid recipient email address: {to}" |
| logger.error(error_msg) |
| return { |
| "status": "error", |
| "content": [ |
| {"text": error_msg} |
| ] |
| } |
| |
| if not html_content.strip(): |
| error_msg = "Email content cannot be empty" |
| logger.error(error_msg) |
| return { |
| "status": "error", |
| "content": [ |
| {"text": error_msg} |
| ] |
| } |
| |
| if not subject.strip(): |
| error_msg = "Email subject cannot be empty" |
| logger.error(error_msg) |
| return { |
| "status": "error", |
| "content": [ |
| {"text": error_msg} |
| ] |
| } |
| |
| |
| try: |
| message = Mail( |
| from_email=settings.SENDGRID_FROM_EMAIL, |
| to_emails=to, |
| subject=subject, |
| html_content=html_content |
| ) |
| except Exception as e: |
| error_msg = f"Failed to construct email message: {str(e)}" |
| logger.error(error_msg) |
| return { |
| "status": "error", |
| "content": [ |
| {"text": error_msg} |
| ] |
| } |
| |
| |
| try: |
| sg = SendGridAPIClient(settings.SENDGRID_API_KEY) |
| response = sg.send(message) |
| |
| |
| if response.status_code in [200, 201, 202]: |
| success_msg = f"Email sent successfully to {to}" |
| logger.info(f"{success_msg}. SendGrid status: {response.status_code}") |
| return { |
| "status": "success", |
| "content": [ |
| {"text": success_msg}, |
| {"json": { |
| "recipient": to, |
| "subject": subject, |
| "status_code": response.status_code, |
| "message_id": response.headers.get("X-Message-Id", "N/A") |
| }} |
| ] |
| } |
| else: |
| error_msg = f"SendGrid returned unexpected status code: {response.status_code}" |
| logger.warning(error_msg) |
| return { |
| "status": "error", |
| "content": [ |
| {"text": error_msg}, |
| {"json": {"status_code": response.status_code, "response_body": str(response.body)}} |
| ] |
| } |
| |
| except Exception as e: |
| error_msg = f"Error sending email to {to}: {str(e)}" |
| logger.error(error_msg) |
| return { |
| "status": "error", |
| "content": [ |
| {"text": error_msg} |
| ] |
| } |
|
|