Step 1 — Email parser

Resend inbound webhook that parses Bayut/PF emails into structured lead data.

2 min read

Setting up the email parser

Step 1: Get a Resend inbound domain

  1. Sign up at resend.com
  2. Buy leads@yourdomain.com (or use a subdomain like leads.steinhoff.systems)
  3. Configure DNS: MX record pointing to Resend, SPF/DKIM for deliverability
  4. In Resend dashboard: enable inbound email, set webhook URL

Step 2: The parser script

# scripts/parse-lead-email.py
import re
import json
from email import message_from_string
from bs4 import BeautifulSoup

def parse_bayut_email(raw_email):
    msg = message_from_string(raw_email)
    payload = msg.get_payload()

    if msg.is_multipart():
        html = ""
        for part in payload:
            if part.get_content_type() == "text/html":
                html = part.get_payload(decode=True).decode()
        break

    soup = BeautifulSoup(html, "html.parser")

    # Bayut email structure (inspected — 2026 version)
    lead = {
        "source": "bayut",
        "name": soup.find("span", {"class": "lead-name"}).text,
        "phone": soup.find("span", {"class": "lead-phone"}).text,
        "budget": soup.find("span", {"class": "lead-budget"}).text,
        "area": soup.find("span", {"class": "lead-area"}).text,
        "timeline": soup.find("span", {"class": "lead-timeline"}).text,
        "property_ref": soup.find("span", {"class": "property-ref"}).text,
        "message": soup.find("div", {"class": "lead-message"}).text,
    }

    # Extract budget number from string like "AED 1.5M" or "1,000,000"
    budget_match = re.search(r'([\d,]+)', lead["budget"])
    if budget_match:
        lead["budget_num"] = int(budget_match.group(1).replace(",", ""))

    return lead

Step 3: The webhook endpoint

# scripts/server.py (Flask)
from flask import Flask, request, jsonify
from parse_lead_email import parse_bayut_email
import json

app = Flask(__name__)

@app.route("/webhook/resend", methods=["POST"])
def handle_lead_email():
    data = request.json
    raw_email = data["email"]["raw"]
    lead = parse_bayut_email(raw_email)

    # Save to database
    save_lead(lead)

    # Trigger qualification flow
    qualify_lead(lead)

    return jsonify({"status": "ok", "lead_id": lead["id"]})

def qualify_lead(lead):
    # Hot: budget > 1M AND timeline < 1 month
    # Warm: budget > 500k AND timeline < 2 months
    # Cold: everything else
    ...

Gotchas

  1. Bayut emails use inline CSS tables — BeautifulSoup handles this but be prepared for weird nesting
  2. Arabic text — make sure you decode UTF-8 properly: raw_email.decode('utf-8')
  3. Multiple properties in one email — some portal emails contain 2–3 leads. Parse them all.
  4. Property ref format — Bayut uses BPT1234567, PF uses PF-789012, Dubizzle uses DUB-3456. Your parser needs to handle all three.

Real-world test

After building this, send yourself a test email from Bayut Pro (request a test lead through the portal). Verify the parser extracts correctly. You will find 3 things wrong with your first regex. Fix them, then re-test.

AI Lead Automation · progress saved in this browser · sign in to sync across devices

Up next

Step 2 — WhatsApp integration

Twilio WhatsApp Business API for instant first-touch messages with read receipts.

1 min