Samfredoly commited on
Commit
46eb21b
·
verified ·
1 Parent(s): 983fa0d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +27 -63
app.py CHANGED
@@ -1,31 +1,21 @@
1
  import logging
2
- import smtplib
3
  import re
4
- from email.mime.text import MIMEText
5
  from fastapi import FastAPI
6
  from pydantic import BaseModel, Field
7
- from aiosmtpd.controller import Controller
8
- from aiosmtpd.handlers import Sink
9
  import uvicorn
10
 
11
  # =======================
12
  # Configuration Settings
13
  # =======================
14
- # SMTP server settings for our own SMTP server (running locally)
15
- SMTP_SERVER_HOST = "localhost" # Hostname for our SMTP server
16
- SMTP_SERVER_PORT = 1025 # Port for our SMTP server (local testing port)
17
-
18
- # SMTP client settings (used by the bot to send emails via our SMTP server)
19
- CLIENT_SMTP_HOST = "localhost" # Must match SMTP_SERVER_HOST for local testing
20
- SMTP_PORT = 1025 # Must match SMTP_SERVER_PORT
21
- SMTP_USER = "noreply@yourdomain.com" # For local testing with a simple SMTP server, these values are not used
22
- SMTP_PASSWORD = "password"
23
 
24
  # =======================
25
  # Logging Configuration
26
  # =======================
27
  logging.basicConfig(level=logging.DEBUG, format="%(asctime)s - %(levelname)s - %(message)s")
28
- logger = logging.getLogger("bot_brain")
29
 
30
  # =======================
31
  # Global Conversation State
@@ -40,34 +30,31 @@ conversations = {}
40
  EMAIL_REGEX = re.compile(r"^[^@]+@[^@]+\.[^@]+$")
41
 
42
  def validate_email(email: str) -> bool:
43
- """Validate an email address using regex."""
44
  return re.match(EMAIL_REGEX, email) is not None
45
 
46
- def send_email(from_addr: str, to_addr: str, subject: str, body: str) -> bool:
47
  """
48
- Sends an email using the SMTP client.
49
- For local testing with our own SMTP server (plain text, no TLS), we remove starttls and login.
50
  """
51
- msg = MIMEText(body)
52
- msg['Subject'] = subject
53
- msg['From'] = from_addr
54
- msg['To'] = to_addr
55
-
56
- logger.debug(f"Preparing to send email from {from_addr} to {to_addr} with subject '{subject}'")
57
-
58
  try:
59
- # Connect to the local SMTP server (plain text)
60
- with smtplib.SMTP(CLIENT_SMTP_HOST, SMTP_PORT) as server:
61
- # For a plain SMTP server running locally (e.g. aiosmtpd Sink), do not call starttls() or login()
62
- server.sendmail(from_addr, [to_addr], msg.as_string())
63
- logger.info(f"Email sent successfully from {from_addr} to {to_addr}")
64
- return True
65
  except Exception as e:
66
- logger.error(f"Error sending email: {e}")
67
  return False
68
 
69
  # =======================
70
- # Pydantic Models
71
  # =======================
72
  class Text(BaseModel):
73
  body: str
@@ -80,7 +67,7 @@ class BotRequest(BaseModel):
80
  message: Message
81
 
82
  # =======================
83
- # FastAPI Application
84
  # =======================
85
  app = FastAPI()
86
 
@@ -88,15 +75,14 @@ app = FastAPI()
88
  async def bot_endpoint(request_data: BotRequest):
89
  payload = request_data.dict(by_alias=True)
90
  logger.debug("Received request payload: %s", payload)
91
-
92
  sender_number = request_data.from_
93
  message_body = request_data.message.text.body.strip()
94
  logger.info("Processing message from %s: '%s'", sender_number, message_body)
95
-
96
  state = conversations.get(sender_number, {})
97
-
98
  if not state:
99
- # Start a new conversation
100
  conversations[sender_number] = {"step": "from"}
101
  response_msg = "Welcome to SMTP Assistant! Please provide your 'From' email address."
102
  else:
@@ -127,40 +113,18 @@ async def bot_endpoint(request_data: BotRequest):
127
  subject = state.get("subject")
128
  body = state.get("body")
129
  logger.info("Attempting to send email from %s to %s with subject '%s'", from_addr, to_addr, subject)
130
- if send_email(from_addr, to_addr, subject, body):
131
  response_msg = f"Email sent successfully from {from_addr} to {to_addr}."
132
  else:
133
  response_msg = "Failed to send email. Please try again later."
134
- # Clear conversation state after sending
135
  del conversations[sender_number]
136
  logger.info("Cleared conversation state for %s", sender_number)
137
  else:
138
  response_msg = "Unrecognized step. Let's start over. Please provide your 'From' email address."
139
  conversations[sender_number] = {"step": "from"}
140
-
141
  logger.debug("Response message to %s: %s", sender_number, response_msg)
142
  return {"status": "success", "message": response_msg}
143
 
144
- # =======================
145
- # SMTP Server (using aiosmtpd)
146
- # =======================
147
- def start_smtp_server():
148
- """
149
- Start our own SMTP server using aiosmtpd.
150
- For simplicity, we use the Sink handler which accepts and prints all emails.
151
- """
152
- handler = Sink()
153
- controller = Controller(handler, hostname=SMTP_SERVER_HOST, port=SMTP_SERVER_PORT)
154
- controller.start()
155
- logger.info(f"SMTP server started at {SMTP_SERVER_HOST}:{SMTP_SERVER_PORT}")
156
- return controller
157
-
158
- # =======================
159
- # Main Execution
160
- # =======================
161
  if __name__ == "__main__":
162
- # Start the SMTP server
163
- smtp_controller = start_smtp_server()
164
-
165
- # Run the FastAPI app using Uvicorn
166
- uvicorn.run("main:app", host="0.0.0.0", port=5000, reload=True)
 
1
  import logging
 
2
  import re
3
+ import requests
4
  from fastapi import FastAPI
5
  from pydantic import BaseModel, Field
 
 
6
  import uvicorn
7
 
8
  # =======================
9
  # Configuration Settings
10
  # =======================
11
+ # URL of the SMTP API endpoint (hosted on Vercel)
12
+ SMTP_API_URL = "https://your-smtp-endpoint.vercel.app/api/send-email" # <--- change this to your deployed Vercel endpoint
 
 
 
 
 
 
 
13
 
14
  # =======================
15
  # Logging Configuration
16
  # =======================
17
  logging.basicConfig(level=logging.DEBUG, format="%(asctime)s - %(levelname)s - %(message)s")
18
+ logger = logging.getLogger("bot_server")
19
 
20
  # =======================
21
  # Global Conversation State
 
30
  EMAIL_REGEX = re.compile(r"^[^@]+@[^@]+\.[^@]+$")
31
 
32
  def validate_email(email: str) -> bool:
 
33
  return re.match(EMAIL_REGEX, email) is not None
34
 
35
+ def send_email_via_api(from_addr: str, to_addr: str, subject: str, body: str) -> bool:
36
  """
37
+ Calls the external SMTP API endpoint to send an email.
 
38
  """
39
+ payload = {
40
+ "from": from_addr,
41
+ "to": to_addr,
42
+ "subject": subject,
43
+ "body": body,
44
+ }
45
+ logger.debug("Calling SMTP API with payload: %s", payload)
46
  try:
47
+ response = requests.post(SMTP_API_URL, json=payload, timeout=10)
48
+ response.raise_for_status()
49
+ result = response.json()
50
+ logger.info("SMTP API response: %s", result)
51
+ return result.get("success", False)
 
52
  except Exception as e:
53
+ logger.error("Error calling SMTP API: %s", e)
54
  return False
55
 
56
  # =======================
57
+ # Pydantic Models for Bot Requests
58
  # =======================
59
  class Text(BaseModel):
60
  body: str
 
67
  message: Message
68
 
69
  # =======================
70
+ # FastAPI Bot Application
71
  # =======================
72
  app = FastAPI()
73
 
 
75
  async def bot_endpoint(request_data: BotRequest):
76
  payload = request_data.dict(by_alias=True)
77
  logger.debug("Received request payload: %s", payload)
78
+
79
  sender_number = request_data.from_
80
  message_body = request_data.message.text.body.strip()
81
  logger.info("Processing message from %s: '%s'", sender_number, message_body)
82
+
83
  state = conversations.get(sender_number, {})
84
+
85
  if not state:
 
86
  conversations[sender_number] = {"step": "from"}
87
  response_msg = "Welcome to SMTP Assistant! Please provide your 'From' email address."
88
  else:
 
113
  subject = state.get("subject")
114
  body = state.get("body")
115
  logger.info("Attempting to send email from %s to %s with subject '%s'", from_addr, to_addr, subject)
116
+ if send_email_via_api(from_addr, to_addr, subject, body):
117
  response_msg = f"Email sent successfully from {from_addr} to {to_addr}."
118
  else:
119
  response_msg = "Failed to send email. Please try again later."
 
120
  del conversations[sender_number]
121
  logger.info("Cleared conversation state for %s", sender_number)
122
  else:
123
  response_msg = "Unrecognized step. Let's start over. Please provide your 'From' email address."
124
  conversations[sender_number] = {"step": "from"}
125
+
126
  logger.debug("Response message to %s: %s", sender_number, response_msg)
127
  return {"status": "success", "message": response_msg}
128
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
  if __name__ == "__main__":
130
+ uvicorn.run("bot_server:app", host="0.0.0.0", port=5000, reload=True)