You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. #
  2. # Copyright 2024 The InfiniFlow Authors. All Rights Reserved.
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. #
  16. from abc import ABC
  17. import json
  18. import smtplib
  19. import logging
  20. from email.mime.text import MIMEText
  21. from email.mime.multipart import MIMEMultipart
  22. from email.header import Header
  23. from email.utils import formataddr
  24. from agent.component.base import ComponentBase, ComponentParamBase
  25. class EmailParam(ComponentParamBase):
  26. """
  27. Define the Email component parameters.
  28. """
  29. def __init__(self):
  30. super().__init__()
  31. # Fixed configuration parameters
  32. self.smtp_server = "" # SMTP server address
  33. self.smtp_port = 465 # SMTP port
  34. self.email = "" # Sender email
  35. self.password = "" # Email authorization code
  36. self.sender_name = "" # Sender name
  37. def check(self):
  38. # Check required parameters
  39. self.check_empty(self.smtp_server, "SMTP Server")
  40. self.check_empty(self.email, "Email")
  41. self.check_empty(self.password, "Password")
  42. self.check_empty(self.sender_name, "Sender Name")
  43. class Email(ComponentBase, ABC):
  44. component_name = "Email"
  45. def _run(self, history, **kwargs):
  46. # Get upstream component output and parse JSON
  47. ans = self.get_input()
  48. content = "".join(ans["content"]) if "content" in ans else ""
  49. if not content:
  50. return Email.be_output("No content to send")
  51. success = False
  52. try:
  53. # Parse JSON string passed from upstream
  54. email_data = json.loads(content)
  55. # Validate required fields
  56. if "to_email" not in email_data:
  57. return Email.be_output("Missing required field: to_email")
  58. # Create email object
  59. msg = MIMEMultipart('alternative')
  60. # Properly handle sender name encoding
  61. msg['From'] = formataddr((str(Header(self._param.sender_name,'utf-8')), self._param.email))
  62. msg['To'] = email_data["to_email"]
  63. if "cc_email" in email_data and email_data["cc_email"]:
  64. msg['Cc'] = email_data["cc_email"]
  65. msg['Subject'] = Header(email_data.get("subject", "No Subject"), 'utf-8').encode()
  66. # Use content from email_data or default content
  67. email_content = email_data.get("content", "No content provided")
  68. # msg.attach(MIMEText(email_content, 'plain', 'utf-8'))
  69. msg.attach(MIMEText(email_content, 'html', 'utf-8'))
  70. # Connect to SMTP server and send
  71. logging.info(f"Connecting to SMTP server {self._param.smtp_server}:{self._param.smtp_port}")
  72. context = smtplib.ssl.create_default_context()
  73. with smtplib.SMTP_SSL(self._param.smtp_server, self._param.smtp_port, context=context) as server:
  74. # Login
  75. logging.info(f"Attempting to login with email: {self._param.email}")
  76. server.login(self._param.email, self._param.password)
  77. # Get all recipient list
  78. recipients = [email_data["to_email"]]
  79. if "cc_email" in email_data and email_data["cc_email"]:
  80. recipients.extend(email_data["cc_email"].split(','))
  81. # Send email
  82. logging.info(f"Sending email to recipients: {recipients}")
  83. try:
  84. server.send_message(msg, self._param.email, recipients)
  85. success = True
  86. except Exception as e:
  87. logging.error(f"Error during send_message: {str(e)}")
  88. # Try alternative method
  89. server.sendmail(self._param.email, recipients, msg.as_string())
  90. success = True
  91. try:
  92. server.quit()
  93. except Exception as e:
  94. # Ignore errors when closing connection
  95. logging.warning(f"Non-fatal error during connection close: {str(e)}")
  96. if success:
  97. return Email.be_output("Email sent successfully")
  98. except json.JSONDecodeError:
  99. error_msg = "Invalid JSON format in input"
  100. logging.error(error_msg)
  101. return Email.be_output(error_msg)
  102. except smtplib.SMTPAuthenticationError:
  103. error_msg = "SMTP Authentication failed. Please check your email and authorization code."
  104. logging.error(error_msg)
  105. return Email.be_output(f"Failed to send email: {error_msg}")
  106. except smtplib.SMTPConnectError:
  107. error_msg = f"Failed to connect to SMTP server {self._param.smtp_server}:{self._param.smtp_port}"
  108. logging.error(error_msg)
  109. return Email.be_output(f"Failed to send email: {error_msg}")
  110. except smtplib.SMTPException as e:
  111. error_msg = f"SMTP error occurred: {str(e)}"
  112. logging.error(error_msg)
  113. return Email.be_output(f"Failed to send email: {error_msg}")
  114. except Exception as e:
  115. error_msg = f"Unexpected error: {str(e)}"
  116. logging.error(error_msg)
  117. return Email.be_output(f"Failed to send email: {error_msg}")