Skip to content

Instantly share code, notes, and snippets.

@scivision
Last active June 6, 2025 21:43
Show Gist options
  • Save scivision/12d4177b743fafc9e5ff37d14bd44e8d to your computer and use it in GitHub Desktop.
Save scivision/12d4177b743fafc9e5ff37d14bd44e8d to your computer and use it in GitHub Desktop.
Extract attachements from .eml email downloaded file from GMail, email client, etc.
#!/usr/bin/env python3
"""
Use Python stdlib "email" to extract attachments from an .eml file
as obtained from an email client or Download from Gmail etc.
based on https://gist.github.com/urschrei/5258588
"""
from pathlib import Path
import email
import email.policy
import email.message
import argparse
import logging
def extract_payload(att: email.message.EmailMessage, extract_dir: Path) -> Path | None:
try:
outfn = att.get_filename()
except AttributeError:
logging.error(f"Could not get attachment filename")
return None
if not outfn:
logging.error(f"Attachment has no filename")
return None
outpath = extract_dir / outfn
with outpath.open("wb") as of:
try:
if pd := att.get_payload(decode=True):
of.write(pd) # type: ignore
return outpath
except TypeError:
logging.error(f"Couldn't get payload for {outfn}")
return None
def extract_attachments(fn: Path, extract_dir: Path) -> None:
count = 0
with fn.open("r") as f:
msg = email.message_from_file(f, policy=email.policy.default)
for att in msg.iter_attachments():
if outpath := extract_payload(att, extract_dir):
count += 1
print(f"Extracted {outpath}")
if count == 0:
raise ValueError(f"No attachment found for file {f.name}")
if __name__ == "__main__":
p = argparse.ArgumentParser(description="extract attachments from .eml file")
p.add_argument("file", help=".eml file to extract attachments from")
p.add_argument(
"-extract_dir", help="directory to extract attachment to", default="."
)
P = p.parse_args()
eml = Path(P.file).expanduser()
extract_attachments(eml, Path(P.extract_dir).expanduser().resolve(strict=True))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment