# Parsing Property Portal Lead Emails Into Clean Records Before Any AI Touches Them

> Source: <https://dev.to/ujjwal_dubey_9/parsing-property-portal-lead-emails-into-clean-records-before-any-ai-touches-them-473g>
> Published: 2026-10-19 05:06:29+00:00

Many property portals still deliver leads to small agencies as notification emails. Before you add an AI assistant to the follow-up, turn those emails into clean, structured records. Clean input makes everything downstream simpler, from dedupe to follow-up timers.

This intake step is the unglamorous start of [real estate lead automation for small agencies](https://www.nxflowai.com/services), and it is worth getting right.

```
{"source": "portal_a", "received_at": "2026-10-19T09:12:00+05:30",
 "name": "...", "phone": "...", "email": "...",
 "listing_ref": "...", "message": "...", "raw_id": "<message-id>"}
```

Each portal formats its emails differently, so write one small parser per sender address and route by the `From` header.

``` php
import re

def parse_portal_a(body: str) -> dict:
    def grab(pattern):
        m = re.search(pattern, body)
        return m.group(1).strip() if m else None
    return {
        "name": grab(r"Name:\s*(.+)"),
        "phone": grab(r"Phone:\s*([+\d][\d\s-]+)"),
        "email": grab(r"Email:\s*(\S+@\S+)"),
        "listing_ref": grab(r"Ref(?:erence)?:\s*(\S+)"),
        "message": grab(r"Message:\s*([\s\S]+?)\n\s*\n"),
    }

PARSERS = {"leads@portal-a.example": parse_portal_a}

def parse(email):
    parser = PARSERS.get(email.sender)
    if parser is None:
        return route_to_human(email, reason="unknown_sender")
    record = parser(email.text_body)
    record.update(source=email.sender, raw_id=email.message_id,
                  received_at=email.date)
    return record
python
REQUIRED = ("listing_ref",)
ONE_OF = ("phone", "email")

def validate(r):
    problems = [f for f in REQUIRED if not r.get(f)]
    if not any(r.get(f) for f in ONE_OF):
        problems.append("no_contact")
    return problems
```

If `validate` returns anything, send the email to a person with the reason attached. Do not guess.

`None` for the phone number creates leads nobody can call.
Dedupe and follow-up timers come after this step. They are much easier when every lead arrives in the same shape.

*Disclosure: I run NxFlowAI, an AI automation agency. Mapping intake like this is part of our first audit, which takes 72 hours for one workflow.*
