Run pytest and email summary in Python

Runs pytest via subprocess, extracts the test summary line, and sends it in an email (mocked for demonstration).

Easy Python 3.9+ Aug 9, 2026 Automation & scripting 13 views 0 copies

Requires third-party packages — install first
pip install pytest

Python code

41 lines
Python 3.9+
import smtplib
import subprocess
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart


def run_tests():
    """Run pytest and capture the summary output."""
    result = subprocess.run(
        ["pytest", "-q"],
        capture_output=True,
        text=True
    )
    return result.stdout + result.stderr


def summarize_tests(test_output):
    """Extract the test summary line from pytest output."""
    for line in test_output.splitlines():
        if "passed" in line or "failed" in line or "error" in line:
            if "==" in line and ("passed" in line or "failed" in line or "error" in line):
                return line.strip()
    return "No summary found"


def send_email_summary(subject, body):
    """Mock email sending by printing the message content."""
    msg = MIMEMultipart()
    msg["From"] = "sender@example.com"
    msg["To"] = "team@example.com"
    msg["Subject"] = subject
    msg.attach(MIMEText(body, "plain"))
    print("=== EMAIL MESSAGE (mock) ===")
    print(str(msg))
    print("=== END EMAIL ===")


if __name__ == "__main__":
    test_output = run_tests()
    summary = summarize_tests(test_output)
    send_email_summary(f"Test Results: {summary}", f"Pytest summary:\n{summary}")

Output

stdout
=== EMAIL MESSAGE (mock) ===
Content-Type: multipart/mixed; boundary="===============...=="
MIME-Version: 1.0
From: sender@example.com
To: team@example.com
Subject: Test Results: 5 passed in 0.10s

--===============...==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit

Pytest summary:
5 passed in 0.10s
--===============...==--

=== END EMAIL ===

How it works

The script uses subprocess.run to execute pytest with quiet mode, capturing both stdout and stderr. The summarize_tests function scans for a line containing 'passed', 'failed', or 'error' that also includes '==', which is typical of pytest summary lines. A MIMEMultipart message is constructed with the summary, and printing it simulates sending without an actual SMTP connection. This mock approach lets you verify the email format before wiring up a real mail server.

Common mistakes

  • Assuming the summary line is always the last line of output.
  • Not combining stdout and stderr, so error messages are missed.
  • Hardcoding SMTP credentials instead of using environment variables.
  • Forgetting to call `server.quit()` when actually sending emails.

Variations

  1. Use `--tb=short` to reduce traceback size in the summary.
  2. Actually send the email with `smtplib.SMTP` and `server.starttls()` for production.

Real-world use cases

  • Automated nightly regression test runs that email the team the pass/fail status.
  • CI/CD pipelines that notify developers when a test suite fails on a specific pull request.
  • Scheduled health checks that run a suite of tests and alert on-call engineers.

Sponsored

Run locally

This sample needs third-party packages, so it cannot run in the browser IDE. Copy the code above, install the packages shown at the top, then run it in your own Python environment.

More from Automation & scripting

Related tutorials and quizzes for this topic.