mimetypes: Detect MIME Types for Files

Published on: August 20, 2026
Reading time: 6 minutes
Folder with files representing MIME types identified with Python mimetypes

The Python standard library mimetypes module connects file extensions with media types used by HTTP, email, storage systems, and desktop applications. It can answer practical questions such as whether a name ending in .png should probably be labeled image/png, whether a JSON download should use application/json, and which fallback should be used when no extension is recognized.

The module is small and convenient, but its limits matter. In most cases it infers the type from a filename or URL. It does not inspect the complete binary payload. Therefore, mimetypes is useful for metadata, routing, headers, and user experience, but it is not sufficient as the only security control for uploads.

What a media type means

A media type normally has the form type/subtype. Common examples include text/html, image/jpeg, application/pdf, and application/zip. Browsers and servers use this value to decide how a resource should be transferred, displayed, downloaded, cached, or processed.

The old MIME name came from email, but media types are now fundamental in HTTP and APIs. The Content-Type response header describes a body. Multipart uploads can declare a type for every part. Internal storage platforms also use types to choose previews, pipelines, retention rules, and malware scanning strategies.

Start with guess_type

import mimetypes

media_type, content_encoding = mimetypes.guess_type("report.pdf")
print(media_type)       # application/pdf
print(content_encoding) # None

The function returns two values. The first is the estimated media type. The second may describe an additional content encoding associated with a suffix, such as gzip. This encoding is not a character set. It describes a compression or transformation layer.

Unknown extensions produce None. Applications should define a clear policy for that outcome. Depending on the product, you may use application/octet-stream, reject the file, request a user choice, or run a deeper content inspection.

Filenames and URLs

The module accepts names and URLs, but query strings and fragments should not become part of the extension. Parse a remote URL first and use its path. The guide to Python urllib.parse explains safe URL decomposition and normalization.

from urllib.parse import urlsplit
import mimetypes

url = "https://example.com/assets/manual.pdf?download=1"
path = urlsplit(url).path
media_type, encoding = mimetypes.guess_type(path)

Type inference does not make the URL trustworthy. Before downloading, validate the scheme and destination, control redirects, enforce timeouts, limit bytes, and protect against SSRF. See Python urllib.request for a bounded HTTP workflow.

Setting Content-Type

A file server can use mimetypes to choose a response header. Use a conservative fallback when the extension is unknown.

import mimetypes
from pathlib import Path

def content_type_for(path: Path) -> str:
    media_type, _ = mimetypes.guess_type(path.name)
    return media_type or "application/octet-stream"

Never let a request freely select an arbitrary local path. Resolve the candidate against an allowed root, block path traversal, and verify that the final path remains inside that root. A correct media type does not make an unsafe path acceptable.

Extensions do not prove content

An attacker can rename an executable to photo.jpg. The module will probably return image/jpeg because it sees the suffix. The underlying bytes can still be an executable, archive, script, or malformed file.

Validate uploads in layers. First, enforce request size, file count, rate limits, and authentication. Next, generate an internal identifier instead of trusting the original name. Then inspect the signature or parse the file with a library designed for that format. Finally, store it outside executable directories and return it with defensive headers.

Use Python tempfile for isolated temporary locations. Use Python hashlib for integrity checks and controlled deduplication.

Compound extensions and compression

A name such as backup.tar.gz combines a container format and a compression encoding. The result can include a TAR type and a gzip encoding. Do not confuse that second value with the type of files found after extraction.

media_type, encoding = mimetypes.guess_type("backup.tar.gz")
print(media_type)
print(encoding)

Compressed uploads need expansion limits, entry-count limits, depth limits, and safe path handling. The guides to Python zipfile and Python tarfile cover archive-specific protections.

Registering custom types

Applications can add mappings for proprietary formats.

import mimetypes

mimetypes.add_type(
    "application/vnd.example.report+json",
    ".rjson",
)
print(mimetypes.guess_type("data.rjson"))

Register critical mappings during application startup and document them. A reusable library should avoid surprising global changes. Tests that alter mappings should isolate or restore the state.

Strict and non-strict mappings

Several functions accept strict. Strict mode focuses on officially registered types. With strict=False, Python may also consider common non-standard mappings known by the platform.

media_type, encoding = mimetypes.guess_type(
    "picture.webp",
    strict=False,
)

Choose a stable policy. Public interoperable services often prefer standardized values. Local tools may accept a broader set. Log the final value you send so production differences can be diagnosed.

Operating-system differences

The available mappings can vary because Python may load information from the operating system. A type recognized on a developer laptop may be missing in a minimal production container. Test the extensions that matter and explicitly register essential mappings.

Do not assume a desktop Linux installation, a Windows host, and a small Docker image expose exactly the same database. Automated tests should verify your supported contract rather than every platform default.

From a type back to an extension

The reverse lookup is available through guess_extension() and guess_all_extensions().

import mimetypes

print(mimetypes.guess_extension("image/jpeg"))
print(mimetypes.guess_all_extensions("image/jpeg"))

More than one suffix can represent the same media type, such as .jpg and .jpeg. Do not use a reverse lookup to reconstruct an original filename. Select a canonical extension defined by your own storage policy.

Character sets are separate

A result of text/plain does not tell you whether bytes use UTF-8, Latin-1, or another encoding. The module does not detect character sets. When your application generates text, declare charset=utf-8 explicitly. For incremental decoding, BOM handling, and error policies, read Python codecs.

Browser sniffing

Browsers sometimes try to infer content when a server sends a missing or incorrect type. That behavior can be dangerous when user uploads are served from the same origin. When appropriate, send X-Content-Type-Options: nosniff and a deliberate Content-Disposition.

Resources that should not execute or render inline can be forced to download. Filenames inside headers still require validation and correct escaping.

A practical API policy

A robust upload API can compare three independent signals: the normalized extension, the type declared by the client, and the result of real content inspection. A disagreement should trigger rejection, quarantine, or review. It should not be silently “fixed” by trusting one signal.

For images, decode the file with a maintained image library and optionally re-encode it. For PDFs, validate structure, size, encryption policy, and downstream behavior. For text, enforce an encoding and byte limit. For archives, inspect entries without extracting blindly.

Testing recommendations

Test uppercase and lowercase extensions, names without extensions, multiple dots, URLs with queries, unknown types, custom registrations, compressed suffixes, and different target platforms. Add hostile examples such as photo.jpg.exe, very long names, control characters, and misleading client headers.

Tests should assert the final application decision, not only the module result. A technically correct guess can still represent a format forbidden by business or security policy.

Common mistakes

Frequent errors include trusting extensions as proof, treating content encoding as a charset, executing a file because its guessed type looks harmless, using original names as paths, accepting unknown values without a fallback policy, assuming identical mappings everywhere, and forgetting download-security headers.

Conclusion

mimetypes is a fast, dependency-free way to infer media types from filenames and URLs. It is valuable for response headers, storage metadata, preview selection, and initial validation. Its central limitation is equally important: it generally studies the name, not the actual bytes.

Use it as one metadata layer alongside content parsing, resource limits, safe storage, and defensive HTTP headers. Consult the official mimetypes documentation and the IANA media types registry.

Share:

Facebook
WhatsApp
Twitter
LinkedIn

Article content

    Related articles

    HTML code on a screen representing parsing with Python html.parser
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python html.parser: Parse HTML

    Learn Python html.parser to extract text, links, and metadata, process HTML incrementally, and avoid confusing parsing with sanitization.

    Ler mais

    Tempo de leitura: 5 minutos
    20/08/2026
    Server rack representing low-level HTTP connections with Python http.client
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python http.client: Low-Level HTTP

    Learn Python http.client for low-level HTTP and HTTPS connections, streaming, headers, TLS, connection reuse, size limits, and errors.

    Ler mais

    Tempo de leitura: 4 minutos
    20/08/2026
    HTML code on a screen representing responsible crawling with Python robotparser
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python robotparser: Read robots.txt

    Learn Python urllib.robotparser to respect robots.txt, crawl-delay, request-rate, sitemaps, caching, and responsible crawling limits.

    Ler mais

    Tempo de leitura: 4 minutos
    20/08/2026
    Keyboard tiles spelling HTTP representing Python urllib.request requests
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python urllib.request: Native HTTP

    Learn Python urllib.request for GET, POST, JSON, downloads, TLS, redirects, proxies, size limits, and robust HTTP error handling.

    Ler mais

    Tempo de leitura: 4 minutos
    19/08/2026
    Ethernet cables connected to a network switch representing Python socketserver services
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python socketserver: Build Servers

    Learn Python socketserver to build TCP and UDP servers with handlers, concurrency, framing, limits, timeouts, and graceful shutdown.

    Ler mais

    Tempo de leitura: 5 minutos
    19/08/2026
    Illuminated server room representing secure TLS connections with Python ssl
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python ssl: Secure TLS Connections

    Learn Python ssl to build TLS clients and servers, validate certificates and hostnames, configure CA trust, minimum versions, and mTLS.

    Ler mais

    Tempo de leitura: 5 minutos
    19/08/2026