Claude Code for mailcap: Python MIME Type Capability Database — Claude Skills 360 Blog
Blog / AI / Claude Code for mailcap: Python MIME Type Capability Database
AI

Claude Code for mailcap: Python MIME Type Capability Database

Published: January 7, 2029
Read time: 5 min read
By: Claude Skills 360

Python’s mailcap module reads /etc/mailcap and ~/.mailcap UNIX files to find programs registered to handle MIME types. import mailcap. Load database: caps = mailcap.getcaps()dict[str, list[dict]] — keys are MIME types like "text/html", "image/png", "application/pdf". Find handler: match, cmd = mailcap.findmatch(caps, "image/jpeg", filename="/tmp/photo.jpg")(entry_dict, cmd_string) or (None, None). Key parameter: mailcap.findmatch(caps, "text/html", key="print", ...) — selects the print= capability instead of the default view=. Template substitution: %s → filename, %t → MIME type, %% → literal %. Wildcards: "image/*" matches any image type; "*" is the global fallback. Note: mailcap is UNIX-specific and reads ~/.mailcap, ~/.mime.types etc.; the spec comes from RFC 1524. Deprecated since Python 3.11 — use only in UNIX sysadmin tools that need native capability lookup. Claude Code generates file preview launchers, MIME type routers, content-type-aware open handlers, and media player selectors.

CLAUDE.md for mailcap

## mailcap Stack
- Stdlib: import mailcap  (Unix only; deprecated Python 3.11)
- Load:   caps = mailcap.getcaps()   # read /etc/mailcap + ~/.mailcap
- Find:   match, cmd = mailcap.findmatch(caps, "image/jpeg", filename="/tmp/a.jpg")
- Key:    mailcap.findmatch(caps, "text/html", key="print", filename="doc.html")
- Note:   returns (None, None) when no handler found
-         cmd is ready to pass to subprocess.run(cmd, shell=True)

mailcap MIME Capability Pipeline

# app/mailcaputil.py — loader, finder, router, launcher, inventory
from __future__ import annotations

import mailcap
import mimetypes
import os
import re
import shlex
import subprocess
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any


# ─────────────────────────────────────────────────────────────────────────────
# 1. Database loading
# ─────────────────────────────────────────────────────────────────────────────

_caps_cache: "dict[str, list[dict[str, Any]]] | None" = None


def get_caps(reload: bool = False) -> dict[str, list[dict[str, Any]]]:
    """
    Return the cached mailcap capability database.
    Call with reload=True to re-read from disk.

    Example:
        caps = get_caps()
        print(list(caps.keys())[:5])
    """
    global _caps_cache
    if _caps_cache is None or reload:
        _caps_cache = mailcap.getcaps()
    return _caps_cache


def list_types(caps: "dict[str, list[dict]] | None" = None) -> list[str]:
    """
    Return all MIME types registered in the mailcap database, sorted.

    Example:
        for t in list_types():
            print(t)
    """
    c = caps or get_caps()
    return sorted(c.keys())


# ─────────────────────────────────────────────────────────────────────────────
# 2. Handler lookup
# ─────────────────────────────────────────────────────────────────────────────

@dataclass
class CapabilityResult:
    """Result of a mailcap handler lookup."""
    mime_type:  str
    key:        str
    found:      bool
    command:    str = ""
    entry:      "dict[str, Any] | None" = None

    def shell_args(self) -> list[str]:
        """Return the command split for subprocess.run with shell=False."""
        return shlex.split(self.command) if self.command else []


def find_handler(
    mime_type: str,
    filename: str = "",
    key: str = "view",
    plist: "list[str] | None" = None,
    caps: "dict[str, list[dict]] | None" = None,
) -> CapabilityResult:
    """
    Find the mailcap handler for a MIME type and optional key.
    Returns a CapabilityResult with found=False if no handler exists.

    Example:
        r = find_handler("text/html", filename="/tmp/page.html")
        if r.found:
            subprocess.run(r.command, shell=True)
    """
    c = caps or get_caps()
    entry, cmd = mailcap.findmatch(
        c, mime_type, key=key,
        filename=filename or "/dev/null",
        plist=plist or [],
    )
    return CapabilityResult(
        mime_type=mime_type,
        key=key,
        found=entry is not None,
        command=cmd or "",
        entry=entry,
    )


def find_handler_for_file(
    path: "str | Path",
    key: str = "view",
    caps: "dict[str, list[dict]] | None" = None,
) -> CapabilityResult:
    """
    Guess the MIME type from the file extension and find its handler.

    Example:
        r = find_handler_for_file("/tmp/report.pdf")
        if r.found:
            subprocess.run(r.command, shell=True)
    """
    p = Path(path)
    mime, _ = mimetypes.guess_type(str(p))
    mime = mime or "application/octet-stream"
    return find_handler(mime, filename=str(p), key=key, caps=caps)


# ─────────────────────────────────────────────────────────────────────────────
# 3. MIME type router
# ─────────────────────────────────────────────────────────────────────────────

@dataclass
class RouteResult:
    """Which handler program is preferred for a given MIME type."""
    mime_type:  str
    program:    str = ""          # extracted program name (first token of command)
    command:    str = ""
    found:      bool = False


def route_mime(
    mime_type: str,
    filename: str = "",
    caps: "dict[str, list[dict]] | None" = None,
) -> RouteResult:
    """
    Return the preferred viewer for mime_type and extract the program name.

    Example:
        r = route_mime("application/pdf")
        print(r.program)   # "evince" or "okular" etc.
    """
    result = find_handler(mime_type, filename=filename, caps=caps)
    program = ""
    if result.found and result.command:
        tokens = shlex.split(result.command)
        program = os.path.basename(tokens[0]) if tokens else ""
    return RouteResult(mime_type=mime_type, program=program,
                       command=result.command, found=result.found)


def inventory(caps: "dict[str, list[dict]] | None" = None) -> list[RouteResult]:
    """
    Return RouteResult for every MIME type in the database.

    Example:
        for r in inventory():
            if r.found:
                print(f"{r.mime_type:30s} → {r.program}")
    """
    c = caps or get_caps()
    results: list[RouteResult] = []
    for mime_type in sorted(c.keys()):
        results.append(route_mime(mime_type, caps=c))
    return results


# ─────────────────────────────────────────────────────────────────────────────
# 4. Safe launcher
# ─────────────────────────────────────────────────────────────────────────────

def launch_viewer(
    path: "str | Path",
    key: str = "view",
    dry_run: bool = False,
) -> "subprocess.CompletedProcess | None":
    """
    Find and launch the mailcap viewer for a file (by extension → MIME type).
    dry_run=True prints the command without executing.
    Returns None if no handler found.

    Example:
        proc = launch_viewer("/tmp/image.png")
        proc = launch_viewer("/tmp/document.pdf", dry_run=True)
    """
    r = find_handler_for_file(path, key=key)
    if not r.found:
        print(f"  No mailcap handler for {r.mime_type}")
        return None
    if dry_run:
        print(f"  [dry-run] {r.command}")
        return None
    return subprocess.run(r.command, shell=True)


def has_handler(mime_type: str, key: str = "view") -> bool:
    """
    Return True if a mailcap handler exists for the given MIME type and key.

    Example:
        has_handler("application/pdf")       # True or False
        has_handler("text/html", key="print")
    """
    return find_handler(mime_type, key=key).found


# ─────────────────────────────────────────────────────────────────────────────
# Demo
# ─────────────────────────────────────────────────────────────────────────────

if __name__ == "__main__":
    print("=== mailcap demo ===")

    if os.name == "nt":
        print("  mailcap is Unix-only — skipping on Windows")
    else:
        caps = get_caps()
        print(f"\n  loaded {len(caps)} MIME type entries from mailcap database")

        # ── list_types ─────────────────────────────────────────────────────────
        print("\n--- list_types (first 10) ---")
        types = list_types(caps)
        for t in types[:10]:
            print(f"  {t}")

        # ── find_handler ──────────────────────────────────────────────────────
        print("\n--- find_handler ---")
        for mime, fname in [
            ("text/html",       "/tmp/page.html"),
            ("application/pdf", "/tmp/doc.pdf"),
            ("image/png",       "/tmp/img.png"),
            ("video/mp4",       "/tmp/film.mp4"),
            ("text/plain",      "/tmp/readme.txt"),
        ]:
            r = find_handler(mime, filename=fname, caps=caps)
            status = f"cmd={r.command[:50]!r}" if r.found else "NOT FOUND"
            print(f"  {mime:25s}: {status}")

        # ── inventory (first 8 found) ─────────────────────────────────────────
        print("\n--- inventory (first 8 with handlers) ---")
        inv = [r for r in inventory(caps) if r.found]
        for r in inv[:8]:
            print(f"  {r.mime_type:30s}{r.program}")

        # ── has_handler ────────────────────────────────────────────────────────
        print("\n--- has_handler ---")
        for mime in ["text/html", "application/pdf", "image/svg+xml", "nope/nope"]:
            print(f"  {mime:30s}: view={has_handler(mime)}")

        # ── launch_viewer dry_run ─────────────────────────────────────────────
        print("\n--- launch_viewer (dry_run) ---")
        for path in ["/tmp/test.html", "/tmp/test.pdf", "/tmp/test.xyz"]:
            print(f"  {path}: ")
            launch_viewer(path, dry_run=True)

    print("\n=== done ===")

For the mimetypes stdlib alternative — mimetypes.guess_type(filename) maps file extensions to MIME type strings, and mimetypes.guess_extension(mime_type) goes the other direction — use mimetypes when you need MIME-type detection from filenames; use mailcap when you additionally need the program registered to handle that MIME type on Unix. For the xdg-open / open / os.startfile alternative — subprocess.run(["xdg-open", filename]) on Linux, subprocess.run(["open", filename]) on macOS, and os.startfile(filename) on Windows delegate MIME handling to the OS desktop environment without any Python lookup — use this approach for consumer desktop apps where you want the system default for any file; use mailcap.findmatch when you need programmatic control over which specific program to invoke or need to inspect available capabilities. The Claude Skills 360 bundle includes mailcap skill sets covering get_caps()/list_types() database helpers, CapabilityResult/find_handler()/find_handler_for_file() lookups, RouteResult/route_mime()/inventory() router, and launch_viewer()/has_handler() utilities. Start with the free tier to try mailcap patterns and MIME handler pipeline code generation.

Keep Reading

AI

Claude Code for email.contentmanager: Python Email Content Accessors

Read and write EmailMessage body content with Python's email.contentmanager module and Claude Code — email contentmanager ContentManager for the class that maps content types to get and set handler functions allowing EmailMessage to support get_content and set_content with type-specific behaviour, email contentmanager raw_data_manager for the ContentManager instance that handles raw bytes and str payloads without any conversion, email contentmanager content_manager for the standard ContentManager instance used by email.policy.default that intelligently handles text plain text html multipart and binary content types, email contentmanager get_content_text for the handler that returns the decoded text payload of a text-star message part as a str, email contentmanager get_content_binary for the handler that returns the raw decoded bytes payload of a non-text message part, email contentmanager get_data_manager for the get-handler lookup used by EmailMessage get_content to find the right reader function for the content type, email contentmanager set_content text for the handler that creates and sets a text part correctly choosing charset and transfer encoding, email contentmanager set_content bytes for the handler that creates and sets a binary part with base64 encoding and optional filename Content-Disposition, email contentmanager EmailMessage get_content for the method that reads the message body using the registered content manager handlers, email contentmanager EmailMessage set_content for the method that sets the message body and MIME headers in one call, email contentmanager EmailMessage make_alternative make_mixed make_related for the methods that convert a simple message into a multipart container, email contentmanager EmailMessage add_attachment for the method that attaches a file or bytes to a multipart message, and email contentmanager integration with email.message and email.policy and email.mime and io for building high-level email readers attachment extractors text body accessors HTML readers and policy-aware MIME construction pipelines.

5 min read Feb 12, 2029
AI

Claude Code for email.charset: Python Email Charset Encoding

Control header and body encoding for international email with Python's email.charset module and Claude Code — email charset Charset for the class that wraps a character set name with the encoding rules for header encoding and body encoding describing how to encode text for that charset in email messages, email charset Charset header_encoding for the attribute specifying whether headers using this charset should use QP quoted-printable encoding BASE64 encoding or no encoding, email charset Charset body_encoding for the attribute specifying the Content-Transfer-Encoding to use for message bodies in this charset such as QP or BASE64, email charset Charset output_codec for the attribute giving the Python codec name used to encode the string to bytes for the wire format, email charset Charset input_codec for the attribute giving the Python codec name used to decode incoming bytes to str, email charset Charset get_output_charset for returning the output charset name, email charset Charset header_encode for encoding a header string using the charset's header_encoding method, email charset Charset body_encode for encoding body content using the charset's body_encoding, email charset Charset convert for converting a string from the input_codec to the output_codec, email charset add_charset for registering a new charset with custom encoding rules in the global charset registry, email charset add_alias for adding an alias name that maps to an existing registered charset, email charset add_codec for registering a codec name mapping for use by the charset machinery, and email charset integration with email.message and email.mime and email.policy and email.encoders for building international email senders non-ASCII header encoders Content-Transfer-Encoding selectors charset-aware message constructors and MIME encoding pipelines.

5 min read Feb 11, 2029
AI

Claude Code for email.utils: Python Email Address and Header Utilities

Parse and format RFC 2822 email addresses and dates with Python's email.utils module and Claude Code — email utils parseaddr for splitting a display-name plus angle-bracket address string into a realname and email address tuple, email utils formataddr for combining a realname and address string into a properly quoted RFC 2822 address with angle brackets, email utils getaddresses for parsing a list of raw address header strings each potentially containing multiple comma-separated addresses into a list of realname address tuples, email utils parsedate for parsing an RFC 2822 date string into a nine-tuple compatible with time.mktime, email utils parsedate_tz for parsing an RFC 2822 date string into a ten-tuple that includes the UTC offset timezone in seconds, email utils parsedate_to_datetime for parsing an RFC 2822 date string into an aware datetime object with timezone, email utils formatdate for formatting a POSIX timestamp or the current time as an RFC 2822 date string with optional usegmt and localtime flags, email utils format_datetime for formatting a datetime object as an RFC 2822 date string, email utils make_msgid for generating a globally unique Message-ID string with optional idstring and domain components, email utils decode_rfc2231 for decoding an RFC 2231 encoded parameter value into a tuple of charset language and value, email utils encode_rfc2231 for encoding a string as an RFC 2231 encoded parameter value, email utils collapse_rfc2231_value for collapsing a decoded RFC 2231 tuple to a Unicode string, and email utils integration with email.message and email.headerregistry and datetime and time for building address parsers date formatters message-id generators header extractors and RFC-compliant email construction utilities.

5 min read Feb 10, 2029

Put these ideas into practice

Claude Skills 360 gives you production-ready skills for everything in this article — and 2,350+ more. Start free or go all-in.

Back to Blog

Get 360 skills free