🚀 Big News: Socket Acquires Coana to Bring Reachability Analysis to Every Appsec Team.Learn more

ser-mail-api

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ser-mail-api

Proofpoint Secure Email Relay Mail API

2.0.3
Maintainers
1

Proofpoint Secure Email Relay Mail API Package

PyPI Downloads
This library implements all the functions of the SER Email Relay API via Python.

Requirements

  • Python 3.9+
  • requests
  • requests-oauth2client
  • pysocks
  • Active Proofpoint SER API credentials

Installing the Package

You can install the tool using the following command directly from GitHub:

pip install git+https://github.com/pfptcommunity/ser-mail-api-python.git

Alternatively, you can install the tool using pip:

# Note: This may not work on Ubuntu 24.04:
pip install ser-mail-api

If you encounter an error similar to the following:

error: externally-managed-environment

× This environment is externally managed
╰─> To install Python packages system-wide, try apt install
    python3-xyz, where xyz is the package you are trying to
    install.

    If you wish to install a non-Debian-packaged Python package,
    create a virtual environment using python3 -m venv path/to/venv.
    Then use path/to/venv/bin/python and path/to/venv/bin/pip. Make
    sure you have python3-full installed.

    If you wish to install a non-Debian packaged Python application,
    it may be easiest to use pipx install xyz, which will manage a
    virtual environment for you. Make sure you have pipx installed.

    See /usr/share/doc/python3.12/README.venv for more information.

note: If you believe this is a mistake, please contact your Python installation or OS distribution provider. You can override this, at the risk of breaking your Python installation or OS, by passing --break-system-packages.
hint: See PEP 668 for the detailed specification.

You should install pipx or configure your own virtual environment and use the command referenced above:

pipx install ser-mail-api

Features

  • Send Emails: Easily compose and send emails with minimal code.
  • Support for Attachments:
    • Attach files from disk
    • Encode attachments as Base64
    • Send byte[] attachments
  • Support for Inline HTML Content:
    • Using the syntax <img src="cid:logo">
    • Content-ID can be set manually or auto-generated
  • HTML & Plain Text Content: Supports both plain text and HTML email bodies.
  • Recipient Management: Add To, CC, and BCC recipients with ease.
  • Reply Management: Add Reply-To addresses to redirect replies.

Quick Start

import json
from ser_mail_api.v1 import *

if __name__ == "__main__":
    client = Client("<client_id>", "<client_secret>")

    # Create a new Message object
    message = Message("This is a test email", MailUser("sender@example.com", "Joe Sender"))

    # Add text content body
    message.add_content(Content("This is a test message", ContentType.Text))

    # Add HTML content body, with embedded image
    message.add_content(Content("<b>This is a test message</b><br><img src=\"cid:logo\">", ContentType.Html))

    # Create an inline attachment from disk and set the cid
    message.add_attachment(Attachment.from_file("C:/temp/logo.png", Disposition.Inline, "logo"))

    # Add recipients
    message.add_to(MailUser("recipient1@example.com", "Recipient 1"))
    message.add_to(MailUser("recipient2@example.com", "Recipient 2"))

    # Add CC
    message.add_cc(MailUser("cc1@example.com", "CC Recipient 1"))
    message.add_cc(MailUser("cc2@example.com", "CC Recipient 2"))

    # Add BCC
    message.add_bcc(MailUser("bcc1@example.com", "BCC Recipient 1"))
    message.add_bcc(MailUser("bcc2@example.com", "BCC Recipient 2"))

    # Add attachments
    message.add_attachment(Attachment.from_base64("VGhpcyBpcyBhIHRlc3Qh", "test.txt"))
    message.add_attachment(Attachment.from_file("C:/temp/file.csv"))
    message.add_attachment(Attachment.from_bytes(b"Sample bytes", "bytes.txt", "text/plain"))

    # Set one or more Reply-To addresses
    message.add_reply_to(MailUser("noreply@proofpoint.com", "No Reply"))

    # Send the email
    result = client.send(message)

    print("HTTP Response: {}/{}".format(result.get_status(), result.get_reason()))
    print("Reason:", result.reason)
    print("Message ID:", result.message_id)
    print("Request ID:", result.request_id)

Attachment MIME Type Deduction Behavior

When creating attachments, the library automatically attempts to determine the MIME type. This detection is based on:

  • The filename argument when using Attachment.from_bytes or Attachment.from_base64.
  • The filepath when using Attachment.from_file.

If the MIME type cannot be determined, an exception will be raised.

from ser_mail_api.v1 import *

if __name__ == "__main__":
    # Create an attachment from disk; the MIME type will be "application/vnd.ms-excel", and disposition will be "Disposition.Attachment"
    Attachment.from_file("C:/temp/file.csv")
    # This will throw an error, as the MIME type is unknown
    Attachment.from_file("C:/temp/file.unknown")
    # Create an attachment and specify the type information. The disposition will be "Disposition.Attachment", filename will be unknown.txt, and MIME type "text/plain"
    Attachment.from_file("C:/temp/file.unknown", filename="unknown.txt")
    # Create an attachment and specify the type information. The disposition will be "Disposition.Attachment", filename will be file.unknown, and MIME type "text/plain"
    Attachment.from_file("C:/temp/file.unknown", mime_type="text/plain")

Inline Attachments and Content-IDs

When creating attachments, they are Disposition.Attachment by default. To properly reference a Content-ID (e.g., <img src="cid:logo">), you must explicitly set the attachment disposition to Disposition.Inline. If the attachment type is set to Disposition.Inline, a default unique Content-ID will be generated.

Using Dynamically Generated Content-ID

The example below demonstrates how to create inline content with a dynamically generated Content-ID inside an HTML message body.

from ser_mail_api.v1 import *

if __name__ == "__main__":
    client = Client("<client_id>", "<client_secret>")

    # Create a new Message object
    message = Message("This is a test email", MailUser("sender@example.com", "Joe Sender"))

    # Create an inline attachment with dynamically generated Content-ID
    logo = Attachment.from_file("C:/temp/logo.png", Disposition.Inline)

    # Add HTML content body, with embedded image
    message.add_content(Content(f"<b>This is a test message</b><br><img src=\"cid:{logo.cid}\">", ContentType.Html))

    # Add the attachment to the message
    message.add_attachment(logo)

    # Add recipients
    message.add_to(MailUser("recipient1@example.com", "Recipient 1"))

    # Send the email
    result = client.send(message)

    print("HTTP Response: {}/{}".format(result.get_status(), result.get_reason()))
    print("Reason:", result.reason)
    print("Message ID:", result.message_id)
    print("Request ID:", result.request_id)

Setting a Custom Content-ID

The example below demonstrates how to create inline content with a custom Content-ID inside an HTML message body.

from ser_mail_api.v1 import *

if __name__ == "__main__":
    client = Client("<client_id>", "<client_secret>")

    # Create a new Message object
    message = Message("This is a test email", MailUser("sender@example.com", "Joe Sender"))

    # Add an inline attachment with a custom Content-ID
    message.add_attachment(Attachment.from_file("C:/temp/logo.png", Disposition.Inline, "logo"))

    # Add HTML content body, with embedded image
    message.add_content(Content(f"<b>This is a test message</b><br><img src=\"cid:logo\">", ContentType.Html))

    # Add recipients
    message.add_to(MailUser("recipient1@example.com", "Recipient 1"))

    # Send the email
    result = client.send(message)

    print("HTTP Response: {}/{}".format(result.get_status(), result.get_reason()))
    print("Reason:", result.reason)
    print("Message ID:", result.message_id)
    print("Request ID:", result.request_id)

Proxy Support

Socks5 Proxy Example:

from ser_mail_api.v1 import *

if __name__ == '__main__':
    client = Client("<client_id>", "<client_secret>")
    credentials = "{}:{}@".format("proxyuser", "proxypass")
    client._session.proxies = {'https': "{}://{}{}:{}".format('socks5', credentials, '<your_proxy>', '8128')}

HTTP Proxy Example (Squid):

from ser_mail_api.v1 import *

if __name__ == '__main__':
    client = Client("<client_id>", "<client_secret>")
    credentials = "{}:{}@".format("proxyuser", "proxypass")
    client._session.proxies = {'https': "{}://{}{}:{}".format('http', credentials, '<your_proxy>', '3128')}

HTTP Timeout Settings

from ser_mail_api.v1 import *

if __name__ == '__main__':
    client = Client("<client_id>", "<client_secret>")
    # Timeout in seconds, connect timeout
    client.timeout = 600
    # Timeout advanced, connect / read timeout
    client.timeout = (3.05, 27)

Known Issues

There is a known issue where empty file content results in a 400 Bad Request error.

{
  "content": "",
  "disposition": "attachment",
  "filename": "empty.txt",
  "id": "1ed38149-70b2-4476-84a1-83e73913d43c",
  "type": "text/plain"
}

🔹 API Response:

Status Code: 400/BadRequest
Message ID:
Reason: attachments[0].content is required
Request ID: fe9a1acf60a20c9d90bed843f6530156
Raw JSON: {"request_id":"fe9a1acf60a20c9d90bed843f6530156","reason":"attachments[0].content is required"}

This issue has been reported to Proofpoint Product Management.

Limitations

  • The Proofpoint API currently does not support empty file attachments.
  • If an empty file is sent, you will receive a 400 Bad Request error.

Additional Resources

For more information, refer to the official Proofpoint Secure Email Relay API documentation:
API Documentation

FAQs

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts