feat(lead-engine): Implement Teams notification and email enhancements [31988f42]

- Enhanced Teams Adaptive Card with precise email send time and re-added emojis to action buttons (" JETZT Aussenden", " STOP Aussendung").
- Modified email sending logic to include HTML signature from `signature.html` and an inline banner image from `RoboPlanetBannerWebinarEinladung.png`.
- Documented future enhancements in `lead-engine/README.md`:
    - Race-condition protection for calendar bookings with a live calendar check.
    - Integration of booking confirmation pages into the WordPress website (iFrame first, then API integration).
This commit is contained in:
2026-03-08 20:01:20 +00:00
parent 8c136174d1
commit 6d4a0564e6
5 changed files with 60 additions and 57 deletions

View File

@@ -28,6 +28,7 @@ DEFAULT_WAIT_MINUTES = 5
SENDER_EMAIL = os.getenv("SENDER_EMAIL", "info@robo-planet.de")
TEST_RECEIVER_EMAIL = "floke.com@gmail.com"
SIGNATURE_FILE_PATH = os.path.join(os.path.dirname(__file__), "signature.html")
BANNER_FILE_PATH = os.path.join(os.path.dirname(__file__), "RoboPlanetBannerWebinarEinladung.png")
# Credentials
AZURE_CLIENT_ID = os.getenv("INFO_Application_ID")
@@ -156,12 +157,25 @@ def book_slot(job_uuid: str, ts: int):
db.close(); return Response("Fehler bei Kalender.", 500)
# --- Workflow Logic ---
def send_email(subject, body, to_email, signature):
def send_email(subject, body, to_email, signature, banner_path=None):
attachments = []
if banner_path and os.path.exists(banner_path):
with open(banner_path, "rb") as f:
content_bytes = f.read()
content_b64 = base64.b64encode(content_bytes).decode("utf-8")
attachments.append({
"@odata.type": "#microsoft.graph.fileAttachment",
"name": "RoboPlanetBannerWebinarEinladung.png",
"contentBytes": content_b64,
"isInline": True,
"contentId": "banner_image"
})
catchall = os.getenv("EMAIL_CATCHALL"); to_email = catchall if catchall else to_email
token = get_access_token(AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_TENANT_ID)
if not token: return
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
payload = {"message": {"subject": subject, "body": {"contentType": "HTML", "content": body + signature}, "toRecipients": [{"emailAddress": {"address": to_email}}]}, "saveToSentItems": "true"}
if attachments: payload["message"]["attachments"] = attachments
requests.post(f"{GRAPH_API_ENDPOINT}/users/{SENDER_EMAIL}/sendMail", headers=headers, json=payload)
def process_lead(request_id, company, opener, receiver, name):
@@ -186,8 +200,10 @@ def process_lead(request_id, company, opener, receiver, name):
for s in suggestions: db.add(ProposedSlot(job_id=job.id, start_time=s, end_time=s+timedelta(minutes=15)))
db.commit()
card = {"type": "message", "attachments": [{"contentType": "application/vnd.microsoft.card.adaptive", "content": {"type": "AdaptiveCard", "version": "1.4", "body": [{"type": "TextBlock", "text": f"🤖 E-Mail an {company}?"}], "actions": [{"type": "Action.OpenUrl", "title": "STOP", "url": f"{FEEDBACK_SERVER_BASE_URL}/stop/{request_id}"},{"type": "Action.OpenUrl", "title": "JETZT", "url": f"{FEEDBACK_SERVER_BASE_URL}/send_now/{request_id}"}]}}]}
requests.post(TEAMS_WEBHOOK_URL, json=card)
send_time = datetime.now(TZ_BERLIN) + timedelta(minutes=DEFAULT_WAIT_MINUTES)
# Using the more detailed card from teams_notification.py
from .teams_notification import send_approval_card
send_approval_card(job_uuid=request_id, customer_name=company, time_string=send_time.strftime("%H:%M"), webhook_url=TEAMS_WEBHOOK_URL, api_base_url=FEEDBACK_SERVER_BASE_URL)
send_time = datetime.now(TZ_BERLIN) + timedelta(minutes=DEFAULT_WAIT_MINUTES)
while datetime.now(TZ_BERLIN) < send_time:
@@ -213,7 +229,7 @@ def process_lead(request_id, company, opener, receiver, name):
{booking_html}
"""
send_email(f"Ihr Kontakt mit RoboPlanet - {company}", email_body, receiver, sig)
send_email(f"Ihr Kontakt mit RoboPlanet - {company}", email_body, receiver, sig, BANNER_FILE_PATH)
job.status = "sent"; db.commit(); db.close()
if __name__ == "__main__":