Skip to main content

Proofpoint Secure Email Relay Admin API

PyPI Downloads
Library implements the Proofpoint Secure Email Relay administrative APIs via Python.

Requirements:

  • Python 3.11+
  • klarient
  • requests
  • requests-oauth2client

Installing the Package

You can install the API library using the following command directly from Github.

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

or can install the API library using pip.

pip install ser-admin-api

For local development from this folder, use an editable install.

python3 -m pip install -e .

Creating an API client object

SER credentials are issued as a principal and secret. SERClient handles the OAuth client-credentials exchange internally using Proofpoint's token endpoint, then applies the issued token to each SER service host.

from ser_admin_api import SERClient

if __name__ == '__main__':
    client = SERClient("<enter_your_principal_here>", "<enter_your_secret_here>")

The client can also be used as a context manager.

from ser_admin_api import SERClient

if __name__ == '__main__':
    with SERClient("<enter_your_principal_here>", "<enter_your_secret_here>") as client:
        print(client.relay.relay_users.path)

Endpoint Examples

Endpoint-focused examples are available under examples/.

examples/
  connector_discovery.py
  connectors.py
  list_management_requests.py
  list_management_unsubscribe.py
  relay_config_discovery.py
  relay_users.py
  reporting_failures.py
  reporting_scoped_resources.py
  reporting_usage.py
  tag_management.py

Copy examples/settings.example.json to settings.json at the project root and add your principal and secret to run them locally. The examples also accept examples/settings.json if you prefer to keep local example settings beside the example files.

The examples are intentionally resource-focused so each file demonstrates one small part of the SER API tree. They are read-only by default. Mutation examples are shown as request shapes or commented calls because connector and relay-user delete operations are not exposed by the documented API.

Resource Paths

The API is modeled as a resource tree. Each resource exposes its path and URL, which can be useful when learning or debugging the wrapper.

from ser_admin_api import SERClient

if __name__ == '__main__':
    client = SERClient("<enter_your_principal_here>", "<enter_your_secret_here>")

    print(client.relay.relay_users.path)
    # /v1/relay-users

    print(client.connector_config.connectors.details.path)
    # /v1/connectors/details

    print(client.list_management.lists.unsubscribe.requests.url)
    # https://list-management.ser.proofpoint.com/v1/lists/unsubscribe/requests

Modeled API Roots

The SER documentation exposes separate hosts for the API areas. SERClient is a facade that owns one Klarient client per service host while sharing one OAuth-backed session.

  • Reporting: https://reporting.ser.proofpoint.com
  • Reporting v2: https://reporting.ser.proofpoint.com
  • Relay User Management: https://relay-config.ser.proofpoint.com
  • Connector Management: https://connector-config.ser.proofpoint.com
  • Tag Management: https://tag-management.ser.proofpoint.com
  • List Management: https://list-management.ser.proofpoint.com

You can override any base URL in the constructor for tests or private deployments.

Querying Relay Users

from ser_admin_api import SERClient
from ser_admin_api.relay_users import RelayUsersQuery

if __name__ == '__main__':
    client = SERClient("<enter_your_principal_here>", "<enter_your_secret_here>")

    relay_users = client.relay.relay_users.retrieve(RelayUsersQuery(page=1, size=100))

    print("Status: {}".format(relay_users.status))
    print("Reason: {}".format(relay_users.reason))
    print("Total Records: {}".format(relay_users.record_count))

    for relay_user in relay_users:
        print(relay_user.relay_user_id)
        print(relay_user.name)
        print(relay_user.status)

Querying Connectors

from ser_admin_api import SERClient
from ser_admin_api.connectors import ConnectorInfoQuery

if __name__ == '__main__':
    client = SERClient("<enter_your_principal_here>", "<enter_your_secret_here>")

    connectors = client.connector_config.connectors.retrieve(ConnectorInfoQuery(page=1, size=100))

    for connector in connectors:
        print(connector.connector_id)
        print(connector.name)
        print(connector.status)

Querying Tags

from ser_admin_api import SERClient
from ser_admin_api.tags import TagInfoQuery

if __name__ == '__main__':
    client = SERClient("<enter_your_principal_here>", "<enter_your_secret_here>")

    tags = client.tag_management.tags.retrieve(TagInfoQuery(page=1, size=100))

    for tag in tags:
        print(tag.tag_id)
        print(tag.name)

Querying Unsubscribe Lists

from ser_admin_api import SERClient
from ser_admin_api.suppression import UnsubscribeListQuery

if __name__ == '__main__':
    client = SERClient("<enter_your_principal_here>", "<enter_your_secret_here>")

    lists = client.list_management.lists.unsubscribe.retrieve(
        UnsubscribeListQuery(page=1, size=100)
    )

    for unsubscribe_list in lists:
        print(unsubscribe_list.list_id)
        print(unsubscribe_list.name)

Querying Reporting Data

from datetime import date, timedelta

from ser_admin_api import SERClient
from ser_admin_api.reporting.failures import ReportInterval
from ser_admin_api.reporting.usage import UsageMetricsRequest, UsageTrafficSummaryQuery, UsageTrendRequest

if __name__ == '__main__':
    client = SERClient("<enter_your_principal_here>", "<enter_your_secret_here>")

    end = date.today()
    start = end - timedelta(days=7)

    traffic = client.reporting.usage.traffic_summary.retrieve(
        UsageTrafficSummaryQuery().with_dates(gte=start, lte=end)
    )
    print(traffic.data.accepted_messages)

    relay_usage = client.reporting.usage.relay_users.retrieve(
        UsageMetricsRequest().with_dates(gte=start, lte=end).with_page(1, 100)
    )
    for row in relay_usage:
        print(row.relay_user_id)
        print(row.total_messages)

    trend = client.reporting.usage.message_trend.retrieve(
        UsageTrendRequest().with_dates(gte=start, lte=end).with_interval(ReportInterval.DAY)
    )
    print(trend.data)

Pagination

List-style resources are pageable. Calling retrieve() returns a Page object. Iterating a pageable resource yields page objects. Calling items() flattens page boundaries and yields typed rows.

from ser_admin_api import SERClient

if __name__ == '__main__':
    client = SERClient("<enter_your_principal_here>", "<enter_your_secret_here>")

    for page in client.relay.relay_users:
        print("Current Page Number: {}".format(page.current_page_number))
        print("Page Size: {}".format(page.page_size))
        print("Total Records: {}".format(page.record_count))
        for relay_user in page:
            print(relay_user.name)
        break

    for relay_user in client.relay.relay_users.items():
        print(relay_user.name)

Common pageable resources include:

client.relay.verified_domains
client.relay.relay_users
client.relay.relay_users.search
client.connector_config.connectors
client.connector_config.connectors.search
client.connector_config.connectors.details
client.connector_config.connectors.details.search
client.tag_management.tags
client.tag_management.tags["tag-id"].notes
client.list_management.lists.unsubscribe
client.list_management.lists.unsubscribe["list-id"].addresses
client.list_management.lists.unsubscribe["list-id"].relay_users
client.list_management.lists.unsubscribe.requests
client.reporting.usage.relay_users
client.reporting.usage.tags
client.reporting.failures.relay_users
client.reporting.failures.tags

Creating Or Updating Resources

Mutation request bodies are typed request objects. Constructor arguments model required or common fields. Builder methods add optional fields while keeping the final JSON body aligned with the SER API.

from ser_admin_api.relay_users import RelayUserCreate

create_request = (
    RelayUserCreate("cluster-23", "Example Relay User")
    .with_allowed_address(mail_from="example.com", header_from="example.com")
    .generate(length=16, allow_lowercase=True, allow_uppercase=True)
    .with_tag("tag-id")
)

print(create_request.to_mapping())
from ser_admin_api.relay_users import RelayUserAllowedAddress, RelayUserUpdate

relay_user = client.relay.relay_users["relay-user-id"].retrieve().data

update_request = RelayUserUpdate(
    allowed_address=[
        RelayUserAllowedAddress(
            mail_from=address.mail_from,
            header_from=address.header_from,
        )
        for address in relay_user.allowed_addresses
    ],
).with_allowed_address(
    mail_from="new.example.com",
    header_from="new.example.com",
)

print(update_request.to_mapping())
from ser_admin_api.connectors import ConnectorCreate

create_request = (
    ConnectorCreate(name="Example Connector", port=587, region="US")
    .with_allowed_ip("192.0.2.10")
)

print(create_request.to_mapping())

Connector and relay-user create/update/status calls modify tenant configuration. The examples show the request shapes without changing existing tenant data.

Typed Response Objects

Responses expose quick access to status, reason, URL, the decoded payload, and the native requests response through the underlying Klarient response object. SER rows are modeled as typed dictionary wrappers: known fields have Pythonic properties, and newly-added API fields remain available through dictionary-style access.

connector = client.connector_config.connectors["connector-id"].retrieve()

print(connector.status)
print(connector.data.connector_id)
print(connector.data.name)

# New or endpoint-specific fields remain available from the underlying mapping.
print(connector.data.get("newFieldFromApi"))

Network Options

Network settings such as proxy, timeout, and SSL verification are configured with RequestsOptions.

from klarient import RequestsOptions, RequestsTimeout
from ser_admin_api import SERClient

if __name__ == '__main__':
    client = SERClient(
        "<enter_your_principal_here>",
        "<enter_your_secret_here>",
        options=RequestsOptions(
            timeout=RequestsTimeout(connect=10, read=600),
            proxy="http://proxy.example.com:3128",
            verify_ssl=True,
        ),
    )

Proxy Support

A single proxy URL is used for both HTTP and HTTPS requests.

SOCKS5 proxy example:

from klarient import RequestsOptions
from ser_admin_api import SERClient

if __name__ == '__main__':
    client = SERClient(
        "<enter_your_principal_here>",
        "<enter_your_secret_here>",
        options=RequestsOptions(
            proxy="socks5h://proxyuser:proxypass@proxy.example.com:8128",
        ),
    )

HTTP proxy example:

from klarient import RequestsOptions
from ser_admin_api import SERClient

if __name__ == '__main__':
    client = SERClient(
        "<enter_your_principal_here>",
        "<enter_your_secret_here>",
        options=RequestsOptions(
            proxy="http://proxyuser:proxypass@proxy.example.com:8080",
        ),
    )

If your environment requires different proxies by scheme, pass a requests-style mapping:

from klarient import RequestsOptions
from ser_admin_api import SERClient

if __name__ == '__main__':
    client = SERClient(
        "<enter_your_principal_here>",
        "<enter_your_secret_here>",
        options=RequestsOptions(
            proxy={
                "http": "http://proxy.example.com:8080",
                "https": "http://secure-proxy.example.com:8080",
            },
        ),
    )

If your environment already uses standard proxy variables, those can also be used.

export HTTP_PROXY="http://proxy.example.com:8080"
export HTTPS_PROXY="http://proxy.example.com:8080"

HTTP Timeout Settings

from klarient import RequestsOptions, RequestsTimeout
from ser_admin_api import SERClient

if __name__ == '__main__':
    client = SERClient(
        "<enter_your_principal_here>",
        "<enter_your_secret_here>",
        options=RequestsOptions(timeout=RequestsTimeout(connect=10, read=600)),
    )

Endpoint Coverage

The wrapper models the reviewed SER API areas:

  • Reporting usage v1 and v2 overview
  • Reporting failures
  • Relay configuration and relay users
  • Connector configuration
  • Tag management
  • List management unsubscribe and unsubscribe requests

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ser_admin_api-0.2.1.tar.gz (64.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ser_admin_api-0.2.1-py3-none-any.whl (78.9 kB view details)

Uploaded Python 3

File details

Details for the file ser_admin_api-0.2.1.tar.gz.

File metadata

  • Download URL: ser_admin_api-0.2.1.tar.gz
  • Upload date:
  • Size: 64.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for ser_admin_api-0.2.1.tar.gz
Algorithm Hash digest
SHA256 8f9993c9885d08b53a840a3f22841143eccd6812e9ea4f0f119df5a1a46c8e20
MD5 02c4dead79a837a37ca37e03aedfd3ac
BLAKE2b-256 5cf4b6402b2ff8405ff70c487e1ddd7b69bf2754d0d4dd8f331916ea72616d80

See more details on using hashes here.

Provenance

The following attestation bundles were made for ser_admin_api-0.2.1.tar.gz:

Publisher: python-publish.yml on pfptcommunity/ser-admin-api-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ser_admin_api-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: ser_admin_api-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 78.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for ser_admin_api-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 672223d627d9140e37bf9b19c68f0a13d06664188f3bf0446e0d4bca784edc29
MD5 d25e51d979eb15a6fa9f19cb37400037
BLAKE2b-256 2ddd8fb549e4f109d7e12065fb8b0ce8dbd7bba2e87e1e64d036fda3c3b77a51

See more details on using hashes here.

Provenance

The following attestation bundles were made for ser_admin_api-0.2.1-py3-none-any.whl:

Publisher: python-publish.yml on pfptcommunity/ser-admin-api-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.3.0

2 files

0.2.2

2 files

This release

0.2.1 This release

2 files

0.2.0

2 files

0.1.0

2 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