Skip to main content

How to Extract a Domain Name from an Email Address in Python

Extracting the domain name from an email address - the part after the @ symbol - is a common task in data cleaning, user analytics, email validation, and spam filtering. For example, from "user@example.com", you need to extract "example.com".

In this guide, you will learn multiple methods to extract domain names from email addresses in Python, from simple string operations to regex-based approaches, along with handling edge cases and batch processing.

The simplest and most readable approach uses Python's built-in split() method to divide the email string at the @ symbol:

email = "user@example.com"

domain = email.split("@")[1]

print(domain)

Output:

example.com

How it works:

  1. split("@") divides the string into a list: ["user", "example.com"].
  2. Index [1] retrieves the second element - the domain name.
tip

This is the recommended approach for most use cases. It's concise, fast, and immediately readable. For single email addresses with standard formatting, split() is all you need.

Extracting Both Username and Domain

email = "john.doe@company.org"

username, domain = email.split("@")

print(f"Username: {username}")
print(f"Domain: {domain}")

Output:

Username: john.doe
Domain: company.org

Using partition()

The partition() method splits a string into exactly three parts: the portion before the separator, the separator itself, and the portion after it:

email = "user@example.com"

before, sep, domain = email.partition("@")

print(domain)

Output:

example.com

This method is useful when you want a clean unpacking without worrying about multiple @ symbols - partition() always splits on the first occurrence.

Using Regular Expressions

For complex validation or pattern matching scenarios, regular expressions provide precise control:

import re

email = "user@example.com"

match = re.search(r"@([a-zA-Z0-9.-]+)", email)

if match:
domain = match.group(1)
print(domain)

Output:

example.com

How it works:

  1. The pattern @([a-zA-Z0-9.-]+) matches the @ symbol followed by one or more valid domain characters.
  2. match.group(1) returns the captured group - the domain name without the @.

Extracting Subdomain, Domain, and TLD

Regex allows you to extract individual parts of the domain:

import re

email = "user@mail.example.co.uk"

match = re.search(r"@(.+)$", email)

if match:
full_domain = match.group(1)
parts = full_domain.split(".")

tld = ".".join(parts[-2:]) if len(parts) > 2 else parts[-1]
print(f"Full domain: {full_domain}")
print(f"Parts: {parts}")

Output:

Full domain: mail.example.co.uk
Parts: ['mail', 'example', 'co', 'uk']

Batch Processing: Extract Domains from Multiple Emails

In real-world applications, you often need to process a list of email addresses:

emails = [
"alice@gmail.com",
"bob@company.org",
"carol@university.edu",
"dave@startup.io",
"eve@gmail.com",
]

# Extract all domains
domains = [email.split("@")[1] for email in emails]
print("All domains:", domains)

# Get unique domains
unique_domains = set(domains)
print("Unique domains:", unique_domains)

# Count emails per domain
from collections import Counter

domain_counts = Counter(domains)
print("Domain counts:", dict(domain_counts))

Output:

All domains: ['gmail.com', 'company.org', 'university.edu', 'startup.io', 'gmail.com']
Unique domains: {'startup.io', 'gmail.com', 'company.org', 'university.edu'}
Domain counts: {'gmail.com': 2, 'company.org': 1, 'university.edu': 1, 'startup.io': 1}

Handling Edge Cases

Emails with No @ Symbol

If the input might not be a valid email address, split("@") can produce unexpected results:

Problem:

invalid = "not-an-email"

domain = invalid.split("@")[1] # IndexError: list index out of range

Fix - validate before extracting:

def extract_domain(email):
"""Safely extract domain from an email address."""
if "@" not in email:
return None
parts = email.split("@")
if len(parts) != 2 or not parts[1]:
return None
return parts[1]

# Test cases
print(extract_domain("user@example.com")) # example.com
print(extract_domain("not-an-email")) # None
print(extract_domain("user@")) # None
print(extract_domain("@example.com")) # example.com
print(extract_domain("a@b@c.com")) # None (because of multiple @ symbols)

Output:

example.com
None
None
example.com
None

Emails with Multiple @ Symbols

Technically, email addresses can contain multiple @ symbols if the local part is quoted (e.g., "user@name"@example.com). For strict parsing:

email = '"user@name"@example.com'

# rsplit splits from the right: always gets the domain correctly
domain = email.rsplit("@", 1)[1]

print(domain)

Output:

example.com
tip

Use rsplit("@", 1) instead of split("@") when there's a possibility of multiple @ symbols. rsplit splits from the right side, and maxsplit=1 ensures only one split occurs - always capturing the domain correctly.

Stripping Whitespace and Normalizing Case

Real-world data often contains leading/trailing whitespace and inconsistent casing:

emails = ["  User@Example.COM  ", "admin@COMPANY.org ", " test@Test.IO"]

cleaned_domains = [
email.strip().split("@")[1].lower()
for email in emails
]

print(cleaned_domains)

Output:

['example.com', 'company.org', 'test.io']

Extracting Domains from a Pandas DataFrame

When working with email data in a DataFrame:

import pandas as pd

df = pd.DataFrame({
"name": ["Alice", "Bob", "Carol"],
"email": ["alice@gmail.com", "bob@company.org", "carol@university.edu"],
})

# Extract domain as a new column
df["domain"] = df["email"].str.split("@").str[1]

print(df)

Output:

    name                 email          domain
0 Alice alice@gmail.com gmail.com
1 Bob bob@company.org company.org
2 Carol carol@university.edu university.edu

Comparison of Methods

MethodReadabilityHandles Edge CasesValidationBest For
split("@")[1]✅ Highest❌ Needs guard❌ NoSimple, trusted input
rsplit("@", 1)[1]✅ High✅ Multiple @❌ NoRobust extraction
partition("@")[2]✅ High✅ First @ only❌ NoClean unpacking
re.search()⚠️ Moderate✅ Yes✅ YesValidation + extraction

Summary

Extracting domain names from email addresses in Python is straightforward with the right approach:

  • Use split("@")[1] for the simplest and fastest extraction - ideal for clean, validated data.
  • Use rsplit("@", 1)[1] for a more robust version that handles edge cases with multiple @ symbols.
  • Use partition("@")[2] for clean three-way unpacking of the email components.
  • Use regular expressions when you need simultaneous validation and extraction, or need to parse complex domain structures.
  • Always validate input before extraction to handle missing @ symbols, empty strings, or malformed addresses.
  • Use .strip().lower() to normalize whitespace and casing in real-world data.