|
2 | 2 | Third party email service configuration for sending emails. |
3 | 3 | """ |
4 | 4 |
|
| 5 | +from typing import Dict, Union |
| 6 | + |
5 | 7 | from smtplib import SMTPException, SMTPAuthenticationError, SMTPSenderRefused |
6 | | -from app.utils import EmailSender |
7 | | -from app.schemas.email import SendEmailRequestBody |
| 8 | +import botocore.exceptions |
| 9 | + |
| 10 | +from app.utils import EmailSender, SESEmailSender |
| 11 | +from app.schemas.email import SendEmailRequestBody, EmailProvider |
8 | 12 |
|
9 | 13 |
|
10 | 14 | class EmailService: |
11 | 15 | """ |
12 | 16 | Service layer for handling email sending logic. |
13 | 17 | """ |
14 | 18 |
|
15 | | - def __init__(self, email_sender: EmailSender): |
| 19 | + def __init__( |
| 20 | + self, email_sender: Dict[EmailProvider, Union[EmailSender, SESEmailSender]] |
| 21 | + ): |
16 | 22 | self.email_sender = email_sender |
17 | 23 |
|
18 | 24 | def send_email(self, email_details: SendEmailRequestBody, body: str): |
19 | 25 | """ |
20 | 26 | Sends an email based on email details. |
21 | | -
|
22 | 27 | Args: |
23 | 28 | email_details (SendEmailRequestBody): Details for the email. |
24 | 29 | body (str): body of the email. |
25 | 30 |
|
26 | 31 | Returns: |
27 | | - bool: True if no failure occured on sending email. |
| 32 | + dict: A response dictionary containing: |
| 33 | + - "success" (bool): Indicates whether the email was sent successfully. |
| 34 | + - "error": Error message if the email sending fails. |
28 | 35 | """ |
29 | 36 | try: |
30 | | - result = self.email_sender.send_email( |
31 | | - to_email=email_details.recipient, |
32 | | - subject=email_details.subject, |
33 | | - body=body, |
34 | | - cc=email_details.cc, |
35 | | - bcc=email_details.bcc, |
36 | | - is_html=True, |
37 | | - ) |
| 37 | + result = self._send_email_by_provider(email_details, body) |
38 | 38 | return result |
39 | | - except SMTPAuthenticationError as exc: |
40 | | - raise PermissionError( |
41 | | - "Failed to authenticate with the SMTP server." |
42 | | - ) from exc |
43 | | - except SMTPSenderRefused as exc: |
44 | | - raise ValueError("Sender address refused by the SMTP server.") from exc |
45 | | - except SMTPException as smtp_exc: |
46 | | - raise ConnectionError(f"SMTP error occurred: {smtp_exc}") from smtp_exc |
| 39 | + except Exception as error: |
| 40 | + self._handle_email_error(error) |
| 41 | + |
| 42 | + def _send_email_by_provider(self, email_details: SendEmailRequestBody, body: str): |
| 43 | + provider = email_details.provider |
| 44 | + sender = self.email_sender.get(provider) |
| 45 | + result = sender.send_email( |
| 46 | + to_email=email_details.recipient, |
| 47 | + subject=email_details.subject, |
| 48 | + body=body, |
| 49 | + cc=email_details.cc, |
| 50 | + bcc=email_details.bcc, |
| 51 | + is_html=True, |
| 52 | + ) |
| 53 | + return result |
| 54 | + |
| 55 | + def _handle_email_error(self, error: Exception): |
| 56 | + if isinstance( |
| 57 | + error, (SMTPAuthenticationError, botocore.exceptions.ClientError) |
| 58 | + ): |
| 59 | + raise PermissionError(f"Authentication failed: {str(error)}") from error |
| 60 | + elif isinstance(error, SMTPSenderRefused): |
| 61 | + raise ValueError(f"Email address refused: {str(error)}") from error |
| 62 | + else: |
| 63 | + raise ConnectionError(f"Email sending failed: {str(error)}") from error |
0 commit comments