56 free macros indexedAll toolsHow to runBlogGitHub ↗

How to Extract Email Addresses from Text in Excel

How to extract every email address from a column of free-form text in Excel: regex, formulas, and a free macro that works on Mac and Windows.

2026-04-28

The "find every email in this column" problem

You have a column of free-form notes: meeting summaries, sales-rep call logs, support tickets, customer feedback. About a third of them mention an email address somewhere in the prose. You need a clean list of those emails. Excel has no built-in "extract email" function. The workarounds are awkward enough that most people end up walking the column by hand.

This guide compares the real options. The right one depends on whether you have one column to clean or a recurring weekly job, and whether you're on Windows or Mac.

TL;DR — Key takeaways

  • A long MID/SEARCH formula can extract one email per cell but breaks on cells with more than one.
  • VBA's VBScript.RegExp is fast and elegant on Windows but does NOT exist on Mac Excel.
  • A hand-rolled VBA scanner that walks each @ works on both Windows and Mac.
  • A free VBA macro built on the hand-rolled approach handles multi-email cells, trailing-period sentences, and writes results to the column on the right.

Where this comes up

Common scenarios:

  • Sales notes: a CRM column with rep notes that occasionally mention contacts ("send the deck to priya@acme.io and cc jordan@acme.io").
  • Customer feedback: a column of free-text responses where the customer left their email.
  • Support tickets: a column of message bodies where the sender's email appears in the body.
  • Meeting minutes: notes pasted from a calendar invite where the email list lives inside paragraphs.

In all of these, the email is buried inside prose, possibly with multiple emails per cell, possibly with punctuation around them.

Method 1: A long MID/SEARCH formula

For exactly one email per cell, you can build a formula that finds the @, walks left and right to find the boundaries, and extracts the substring.

=MID(A2, FIND("@", A2) - LEFT_OFFSET, EMAIL_LENGTH)

Constructing LEFT_OFFSET and EMAIL_LENGTH requires nested IFs and SEARCH calls that depend on knowing what character precedes and follows each email.

The catch: for cells with multiple emails, this formula returns only the first one. For cells with no email, it returns #VALUE!. For emails ending a sentence (...send to alex@example.com.), the trailing period gets included unless you add another wrapper.

For one-off use on simple data, a formula works. For real-world prose with multiple emails per cell, it doesn't scale.

Method 2: VBA with VBScript.RegExp (Windows only)

If you're on Windows Excel, VBScript.RegExp gives you full regex power.

Public Function ExtractEmails(ByVal s As String) As String
    Dim regex As Object
    Set regex = CreateObject("VBScript.RegExp")
    regex.Pattern = "[A-Za-z0-9._+%-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}"
    regex.Global = True
    Dim matches As Object
    Set matches = regex.Execute(s)
    Dim out As String, m As Object
    For Each m In matches
        If Len(out) > 0 Then out = out & ", "
        out = out & m.Value
    Next m
    ExtractEmails = out
End Function

Drop this in a module, then =ExtractEmails(A2) in a column writes a comma-separated list of emails to each cell.

The catch: VBScript.RegExp does NOT exist on Mac Excel. Run this on a Mac and you get a runtime error. For cross-platform code you need a different approach.

Method 3: Hand-rolled VBA scanner (cross-platform)

The trick is to walk each @ in the string and expand outward to find the local part (left of @) and the domain (right of @), checking whether each character is a valid email character.

This is what the Extract Email Addresses From Text macro does. It works on both Windows and Mac because it avoids the VBScript.RegExp dependency entirely.

Steps:

  1. Select the column or range of free-form text to scan.
  2. Make sure the column to the right is empty (the macro writes results there).
  3. Press Alt + F8, pick ExtractEmailsFromText, click Run.
  4. The macro extracts every email-shaped substring and writes them, comma-separated, to the cell directly to the right.

The popup at the end reports total emails found and how many cells contained at least one.

What counts as a "valid" email?

The macro's pattern: local-part@domain.tld where:

  • The local part has letters, digits, dots, underscores, hyphens, plus signs, or percent signs.
  • The domain has letters, digits, dots, hyphens.
  • The TLD is at least 2 letters.
  • Trailing dots and hyphens (from sentence punctuation) are trimmed automatically.

So priya@acme.io, support+billing@example.co.uk, and r_smith@subdomain.example.com all match. Things that look email-ish but aren't (like @handle for a Twitter mention) are rejected because there's no . after the @.

Comparison: which method to use

MethodMulti-email cellsTrailing periodWorks on MacSetup time
MID/SEARCH formulaFirst onlySometimesYes5 min per formula version
VBScript.RegExp UDFYesYesNo5 min
Hand-rolled scanner macroYesYes (auto-trimmed)Yes5 sec (after install)

Common scenario: cleaning a sales notes export

Every Friday you pull notes from the team's note-taking app to feed updates into the CRM. Notes are paragraph-style, about 600 rows, a third mentioning an email.

  1. Make sure column G (the column to the right of notes) is empty.
  2. Select the notes column.
  3. Run Extract Email Addresses From Text.
  4. Column G now has the emails for each row, comma-separated when there's more than one.
  5. (Optional) Use Text to Columns on G with , as delimiter to split multi-email cells into separate columns.

Elapsed: about 5 seconds for the macro plus 30 seconds for the optional split.

Frequently asked questions

Why does the result come back as one string per row instead of one email per row?

Keeping the row count of the output the same as the input makes the macro safe to run on any column position. If we exploded multi-email cells into multiple rows, we'd shift every row below them and break aligned data in adjacent columns. To get one email per row afterward, run Text to Columns on the result with , as the delimiter, then transpose if needed.

What if my text mentions an email that ends a sentence with a period?

Handled. The scanner trims trailing dots and hyphens before validating, so "send to alex@example.com." correctly extracts alex@example.com without the trailing period.

Does it find emails inside HTML or angle brackets?

Yes for the email itself, but the angle brackets around it (<alex@example.com> from email signatures) are stripped because they're not valid email characters and the scanner treats them as boundaries. So you get the clean email without the brackets.

Will it find emails with international characters in the local part?

The macro's character set is ASCII-only (a-z, A-Z, 0-9, plus ._+-%). Emails with international characters in the local part (like маша@example.ru) won't match. International TLDs (like .co.uk or .tech) work fine because they're ASCII. Internationalized email addresses are a small minority of real-world data; if you have them, you'd need a more permissive Unicode scanner.

Can I undo it?

Yes, Ctrl/Cmd + Z right after running. The macro only writes to the column to the right of your selection, so undo cleanly removes the extracted column without touching the source text.

What to do next

If you also need to extract phone numbers from the same notes, the Clean Phone Numbers macro can run on a column where you've copy-pasted any phone-number text. If the next step is splitting names into First/Last for a mail merge, see Split Full Names Into First and Last. For the source notes themselves, Trim Whitespace From All Cells is a good prep step before any extraction.