Skip to main content

yomail (読メール)

yomail extracts body text from Japanese business emails. It uses a CRF (Conditional Random Field) model to classify each line, then assembles the body from labeled lines.

Features

  • Handles formal and informal Japanese business emails
  • Detects and excludes signatures, greetings, closings, quoted content
  • Works with forwarded emails, replies, and inline quotes
  • Returns confidence scores for quality control
  • Small model size (12 KB)
  • Fast inference (~10-30ms)

Installation

pip install yomail

Requires Python 3.12+.

Usage

from yomail import EmailBodyExtractor

extractor = EmailBodyExtractor()

# Raises on failure
body = extractor.extract(email_text)

# Returns None on failure
body = extractor.extract_safe(email_text)

# Full result with metadata
result = extractor.extract_with_metadata(email_text)
print(result.body)
print(result.confidence)
print(result.signature_detected)

Example

Input:

株式会社サンプル
田中様

お世話になっております。
山田です。

先日ご依頼いただいた資料を添付いたします。
ご確認のほどよろしくお願いいたします。

以上

--
山田太郎
株式会社テスト
TEL: 03-1234-5678

Output:

お世話になっております。
山田です。

先日ご依頼いただいた資料を添付いたします。
ご確認のほどよろしくお願いいたします。

以上

How It Works

The extraction pipeline:

  1. Normalize — Line endings, neologdn normalization, NFKC
  2. Analyze structure — Quote depth, forward/reply headers, delimiters
  3. Extract features — Position, character ratios, pattern matches
  4. Label with CRF — GREETING, BODY, CLOSING, SIGNATURE, QUOTE, OTHER
  5. Assemble body — Find signature boundary, handle inline quotes, merge blocks

See ARCHITECTURE.md for details.

Label Scheme

Label Description
GREETING Opening (お世話になっております)
BODY Main content
CLOSING Closing (よろしくお願いいたします)
SIGNATURE Sender information
QUOTE Quoted content
OTHER Separators, blank lines

Performance

Evaluated on 19,642 synthetic test emails:

Metric Value
Content match 97.9%
Acceptable rate 98.0%
Confident wrong 0.14%

See PERFORMANCE.md for details.

Exceptions

from yomail import (
    ExtractionError,      # Base class
    InvalidInputError,    # Empty or invalid input
    NoBodyDetectedError,  # No body found
    LowConfidenceError,   # Confidence below threshold
)

Configuration

extractor = EmailBodyExtractor(
    model_path="path/to/model.crfsuite",  # Custom model
    confidence_threshold=0.5,              # Minimum confidence
)

Development

# Setup
uv sync

# Run tests
uv run pytest

# Type check
uv run ty check

# Lint
uv run ruff check .

Training

Training data is generated by the yasumail project.

# Train model
python scripts/train.py data/training.jsonl -o models/email_body.crfsuite

# Evaluate
python scripts/evaluate.py data/test.jsonl

Dependencies

Metadata

Release files for yomail 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for yomail 0.1.1
File Size Uploaded
yomail-0.1.1.tar.gz 194.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for yomail 0.1.1
File Interpreter ABI Platform
yomail-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 333.5 kB

Release files / yomail-0.1.1.tar.gz

Download URL yomail-0.1.1.tar.gz
Size 194.4 kB
Tags Source
SHA-256 checksum
How to use checksums
a891cb6ae70372c6781d212cc0b728b8cb78e354e2baf3abf0cd4b90779e528a
BLAKE2b-256 checksum
How to use checksums
ee3b7f2d2f448bedea95ad36debabae54c7450afb6130c8c3a761b55531b7d09
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jan 28, 2026.

Transparency log

Release files / yomail-0.1.1-py3-none-any.whl

Download URL yomail-0.1.1-py3-none-any.whl
Size 139.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6a2cad4e44566389c0baa18c279dee2b0c504958afaf7955be9eaafa0bc6558d
BLAKE2b-256 checksum
How to use checksums
cf9af6e76c108e9e06a8a9212bf21625f15c9fabaf444a844ccbb3c88f74939a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jan 28, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page