Skip to content

How to Send Multipart/Form-Data Requests in Python with 'requests'

Learn how to upload files and send complex form data in Python using requests with the files parameter or requests-toolbelt for advanced multipart encoding.

Sending data using multipart/form-data encoding is essential for file uploads and submitting complex forms via HTTP POST requests.

This guide explores how to send multipart/form-data requests using the popular requests library in Python, covering scenarios with and without file uploads, and introducing the requests-toolbelt for more advanced control.

Sending Multipart/Form-Data with the files Parameter

The requests library automatically uses multipart/form-data encoding when you provide the files argument to requests.post().

Sending Data Without Actual Files

You can use the files parameter even if you're not uploading files. This forces the Content-Type header to multipart/form-data.

import requests
from pprint import pprint

url = 'https://httpbin.org/post'
response = requests.post(
    url,
    files={'id': '1', 'site': 'tutorialreference.com'}, # Use files param for multipart
    timeout=30
)

print(f"Status Code: {response.status_code}")
if response.ok:
    pprint(response.json().get('headers'))

Output:

Status Code: 200
{'Accept': '*/*',
 'Accept-Encoding': 'gzip, deflate',
 'Content-Length': '...',
 'Content-Type': 'multipart/form-data; boundary=...', # Correct header
 'Host': 'httpbin.org', ... }
  • The files parameter can be used to send any data using multipart/form-data encoding.

Sending Files

To upload a file, provide a file object opened in binary read mode ('rb') within the files dictionary:

import requests

url = 'https://httpbin.org/post'
try:
    with open('data.json', 'rb') as f:
        files_to_upload = {'file': f}
        response = requests.post(url, files=files_to_upload, timeout=30)

    print(response.text)
    print(f"Status Code: {response.status_code}")

except FileNotFoundError:
    print("Error: data.json not found.")
except requests.exceptions.RequestException as e:
    print(f"Request failed: {e}")

Explicitly Setting Filename, Content-Type, and Headers

For more control over file uploads, you can provide a tuple as the value in the files dictionary. The tuple format allows specifying (filename, file_object, content_type, custom_headers).

import requests

url = 'https://httpbin.org/post'
try:
    with open('example.xlsx', 'rb') as f:
        files_spec = {
            'file': (
                'custom_filename.xlsx',     # Custom filename
                f,                          # File object
                'application/vnd.ms-excel', # Specific Content-Type
                {'Expires': '0'}            # Custom headers
                )
            }
        response = requests.post(url, files=files_spec, timeout=30)

    print(response.text)
    print(f"Status Code: {response.status_code}")

except FileNotFoundError:
    print("Error: example.xlsx not found.")
except requests.exceptions.RequestException as e:
    print(f"Request failed: {e}")
  • Plain Text Fields: To send regular form fields alongside files using the files parameter structure, set the filename part of the tuple to None:
    files_with_text = {
        'session_id': (None, 'some_session_value'),         # Plain text field
        'upload': ('report.txt', open('report.txt', 'rb'))  # File field
    }
  • String as File Content: You can also provide a string directly as the file content:
    files_string_content = {
        'file': (
            'example.csv',
            'some,data,to,send\nanother,row,to,send\n'      # String content
        )
    }

Sending Multipart/Form-Data with requests-toolbelt

The requests-toolbelt library offers the MultipartEncoder for more complex scenarios and streaming uploads.

Installing requests-toolbelt

pip install requests-toolbelt
pip3 install requests-toolbelt

Using MultipartEncoder

import requests
from requests_toolbelt.multipart.encoder import MultipartEncoder

url = 'https://httpbin.org/post'

try:
    with open('example.xlsx', 'rb') as f:
        multipart_data = MultipartEncoder(
            fields={
                'field1': 'value1',
                'field2': 'value2',
                'file': ('custom_name.xlsx', f, 'application/vnd.ms-excel')
            }
        )

        response = requests.post(
            url,
            data=multipart_data,                                    # Pass encoder to 'data'
            headers={'Content-Type': multipart_data.content_type},  # Set header from encoder
            timeout=30
        )

    print(response.text)
    print(f"Status Code: {response.status_code}")

except FileNotFoundError:
    print("Error: example.xlsx not found.")
except requests.exceptions.RequestException as e:
    print(f"Request failed: {e}")
  • Create a MultipartEncoder instance, defining fields with their names, values, and optional content types.
  • Pass the MultipartEncoder object to the data parameter of requests.post().
  • Crucially, set the Content-Type header using multipart_data.content_type.

Conclusion

This guide demonstrated how to send multipart/form-data requests using Python's requests library.

You learned the primary method using the files parameter for both simple data and file uploads, how to customize file details using tuples, and how to use the requests-toolbelt library for more advanced multipart encoding. Choosing the right method depends on the complexity of the data and files you need to send.

Navigation