How to match support tickets to customer accounts
By the Analistable team · Updated · 6 min read
Ticket exports identify the requester by email; your account list has domain, plan and revenue. Extract the email domain from each ticket with =LOWER(TEXTAFTER([@Requester], "@")), join to accounts on domain, then pivot tickets by plan and priority. Accounts with many urgent tickets and falling usage are the ones to call first.
Part of our guide: How to join spreadsheets on a common column
Join by domain
Domain =LOWER(TEXTAFTER([@[Requester email]], "@"))
Account =XLOOKUP([@Domain], Accounts[Domain], Accounts[Account], "Unknown")
Plan =XLOOKUP([@Domain], Accounts[Domain], Accounts[Plan], "")Exclude free email domains (gmail.com, outlook.com…) from domain matching — match those on the full email against your user list instead.
Tickets by plan and priority
| Plan | Accounts | Tickets | Urgent | Tickets per account |
|---|---|---|---|---|
| Starter | 420 | 610 | 22 | 1.5 |
| Pro | 85 | 340 | 31 | 4 |
| Enterprise | 12 | 96 | 18 | 8 |
Enterprise accounts raise eight times as many tickets per account as Starter — expected for larger teams, but the urgent share (19% vs 4%) is worth a closer look.
Accounts at risk
Add usage from your product analytics export (logins or active users per account, last month vs previous month) with the same domain key, then filter accounts where usage fell by more than 20% and urgent tickets rose. That combination is a stronger churn signal than either alone.
Several data sources joined on one key is the core pattern in combining data from multiple sources.
Mapping domains that don't match
Some customers email from several domains (a parent company and subsidiaries, or a regional domain). Add an aliases table — domain → account — and look up through it before falling back to the account list:
Account =IFERROR(XLOOKUP([@Domain], Aliases[Domain], Aliases[Account]),
XLOOKUP([@Domain], Accounts[Domain], Accounts[Account], "Unknown"))Review the Unknown tickets once a month and add their domains to the aliases table.
Measures worth tracking
- Tickets per account per month, by plan.
- Share of urgent or high-priority tickets.
- Median first-response and resolution time by plan — compare with what each plan promises.
- Accounts whose ticket volume doubled month over month.
Step by step
- Export tickets with ticket ID, requester email, created date, priority, status and, if available, first-response and resolution times. Field names vary between helpdesk tools.
- Export accounts from your CRM or billing system with account name, primary domain, plan and revenue.
- Add Domain, Account and Plan to the tickets table with the formulas above.
- Add a Month column with
=TEXT([@Created], "yyyy-mm"). - Build a pivot table with Plan in rows and Priority in columns, counting ticket IDs.
TEXTAFTER is only in Excel 365. In Excel 2019, extract the domain with =LOWER(MID([@[Requester email]], FIND("@", [@[Requester email]]) + 1, 100)) and use INDEX/MATCH in place of XLOOKUP. In Google Sheets, =LOWER(REGEXEXTRACT(B2, "@(.+)$")) returns the domain, and XLOOKUP works as in Excel 365.
Free domain? =ISNUMBER(MATCH([@Domain], FreeDomains[Domain], 0))
Account =IF([@[Free domain?]],
XLOOKUP(LOWER([@[Requester email]]), Users[Email], Users[Account], "Unknown"),
XLOOKUP([@Domain], Accounts[Domain], Accounts[Account], "Unknown"))A small FreeDomains table (gmail.com, outlook.com, hotmail.com, yahoo.com and the providers common in your markets) routes those tickets to the full-email lookup.
Second example: one account over three months
| Month | Tickets | Urgent | Active users | Change in users |
|---|---|---|---|---|
| July | 6 | 1 | 140 | — |
| August | 9 | 2 | 131 | −6% |
| September | 15 | 6 | 104 | −21% |
Tickets more than doubled from July to September (6 to 15) while active users fell by about a quarter (140 to 104, −26%). The usage drop exceeds the 20% threshold in September alone, and urgent tickets went from 1 to 6: this account goes to the top of the list for a call.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Many Unknown tickets | Accounts list holds website domains, users email from another domain | Add those domains to the aliases table |
| Tickets from resellers linked to the reseller | Partner raising tickets for end customers | Use the organisation field from the helpdesk if it's set |
| One big account split in two | Subsidiary domain listed as its own account | Map the subsidiary domain to the parent in the aliases table |
| Counts differ from the helpdesk report | Merged or spam tickets included in the export | Filter out merged, deleted and spam statuses |
To check the result, tickets matched to accounts plus Unknown tickets should equal the export's row count; aim to push Unknown below a small share each month. For the join technique, see joining two spreadsheets on a common column and the guide to answering questions across spreadsheets.
Doing it in SQL
For a year of tickets, a query is quicker than formulas. This runs in DuckDB (in SQLite, replace split_part with substr(email, instr(email, '@') + 1)):
SELECT COALESCE(al.account, a.account, 'Unknown') AS account,
COALESCE(a.plan, '') AS plan,
COUNT(*) AS tickets,
SUM(t.priority = 'Urgent') AS urgent
FROM tickets t
LEFT JOIN aliases al ON al.domain = LOWER(split_part(t.requester_email, '@', 2))
LEFT JOIN accounts a ON a.domain = LOWER(split_part(t.requester_email, '@', 2))
GROUP BY 1, 2
ORDER BY urgent DESC, tickets DESC;The aliases table is checked first, then the main accounts list, matching the order of the spreadsheet formula. Make sure each domain appears only once in each table, or tickets will be counted twice.
Common mistakes
- Matching on display name instead of email, when many requesters share names.
- Counting tickets per account without normalising for account size.
- Comparing this month's tickets with an account list exported after customers changed plan.
- Including internal test tickets raised from your own domain.
Repeating it every month
- Export the last month's tickets and a fresh account list.
- Paste them into the same tables; Domain, Account and Plan fill in automatically.
- Review Unknown tickets and add new domains to the aliases table.
- Refresh the pivot and compare tickets per account and urgent share with the previous month.
- Send the list of at-risk accounts to account owners with the ticket count and usage change.
Keep a dated copy of each month's summary. Trends over three or more months are far more reliable than a single spike, which may just be one incident affecting a large customer.
Frequently asked questions
- How do I link helpdesk tickets to customer accounts?
- Extract the requester's email domain and match it to the domain on your account list, or match on full email against your user list.
- How do I extract the domain from an email in Excel?
- Use =LOWER(TEXTAFTER(email, "@")) in Microsoft 365, or =LOWER(MID(email, FIND("@", email) + 1, 100)) in older versions.
- Which accounts should I prioritise?
- Those combining a rise in urgent tickets with falling product usage.
- What about tickets from free email domains like gmail.com?
- Match those on the full email address against your user list instead of the domain.
- Can I do this in Google Sheets?
- Yes. Use REGEXEXTRACT(email, "@(.+)$") for the domain and XLOOKUP or VLOOKUP to match accounts.
- How do I count tickets per account per month?
- Add a Month column with TEXT(created, "yyyy-mm") and pivot with account in rows and month in columns.
- How do I extract the email domain in Excel 2019?
- Use MID with FIND: =LOWER(MID(A2, FIND("@", A2) + 1, 100)) returns everything after the @.
- How do I link tickets from subsidiaries to the parent account?
- Add the subsidiary domains to an aliases table that maps each domain to the parent account, and look up through it before the main account list.
- How do I spot accounts at risk from ticket data?
- Join product usage by the same domain key and filter accounts where usage fell sharply while urgent tickets rose over the same months.
- Why don't my ticket counts match the helpdesk dashboard?
- The export may include merged, deleted or spam tickets, or use a different date field. Filter those statuses and use the created date on both sides.