Skip to main content

Suomi.fi messages for City of Helsinki Django apps

Project description

django-helsinki-suomifi-messages

Suomi.fi Messages client for City of Helsinki Django apps. See the API reference for endpoint details.

  • Send electronic messages to recipients with active Suomi.fi mailboxes
  • Send multichannel messages (electronic or paper mail, depending on mailbox status)
  • Send paper mail without a personal identity code or business ID
  • Check whether recipients have active Suomi.fi mailboxes
  • Retrieve message events and read received messages
  • Upload and download attachments

Contents

Installation

Requires Python 3.10+ and Django 5.2+.

pip install django-helsinki-suomifi-messages

No changes to INSTALLED_APPS are needed; this is a pure client library.

Configuration

Add the following to your Django settings:

# Suomi.fi API credentials
SUOMIFI_USERNAME = "your-api-username"
SUOMIFI_PASSWORD = "your-api-password"
SUOMIFI_SERVICE_ID = "your-service-id"

# Posti Messaging Oy credentials (required for paper mail only)
# Obtained during paper mail deployment:
# https://kehittajille.suomi.fi/services/messages/deployment/deployment-of-the-printing-enveloping-and-distribution-service
SUOMIFI_POSTI_EMAIL = "your-posti-email"
SUOMIFI_POSTI_USERNAME = "your-posti-username"
SUOMIFI_POSTI_PASSWORD = "your-posti-password"

All settings default to an empty string if not set. SUOMIFI_USERNAME, SUOMIFI_PASSWORD, and SUOMIFI_SERVICE_ID can also be passed directly to the relevant client methods. Posti credentials (SUOMIFI_POSTI_*) must always be configured in Django settings.

Quick start

from suomifi_messages import SuomiFiClient
from suomifi_messages.schemas import Address, BodyFormat

client = SuomiFiClient()  # QA environment; use type="prod" for production
client.login()            # uses SUOMIFI_USERNAME / SUOMIFI_PASSWORD from settings

recipient_address = Address(
    name="Matti Meikäläinen",
    street_address="Esimerkkikatu 1",
    zip_code="00100",
    city="Helsinki",
    country_code="FI"
)
sender_address = Address(
    name="Helsingin kaupunki",
    street_address="Lähettäjänkatu 1",
    zip_code="00100",
    city="Helsinki",
    country_code="FI"
)

with open("letter.pdf", "rb") as f:
    attachment_id = client.upload_attachment("letter.pdf", f)

message_id, external_id = client.send_multichannel_message(
    title="This is a title",
    body="Hello, world!",
    body_format=BodyFormat.TEXT,
    recipient_id="123456-789A",
    recipient_address=recipient_address,
    sender_address=sender_address,
    paper_mail_attachment_id=attachment_id,
)

Usage

Creating a client

from suomifi_messages import SuomiFiClient

# QA environment (default)
client = SuomiFiClient()

# More explicit
client = SuomiFiClient(type="qa")

# Production environment
client = SuomiFiClient(type="prod")

Authentication

# Uses SUOMIFI_USERNAME and SUOMIFI_PASSWORD from Django settings
client.login()

# Or pass credentials explicitly
client.login(username="user", password="pass")

# Change password; re-login required afterwards (token is invalidated)
client.change_password(current_password="old-pass", new_password="new-pass")

Checking mailbox status

# Check multiple recipients at once
active_ids = client.check_mailboxes(["123456-789A", "987654-321B"])

# Check a single recipient
has_mailbox = client.check_mailbox("123456-789A")  # True / False

Sending a multichannel message

A multichannel message is delivered electronically to recipients with an active mailbox, or as paper mail to those without:

from suomifi_messages.schemas import Address, BodyFormat

recipient_address = Address(
    name="Matti Meikäläinen",
    street_address="Esimerkkikatu 1",
    zip_code="00100",
    city="Helsinki",
    country_code="FI"
)
sender_address = Address(
    name="Helsingin kaupunki",
    street_address="Lähettäjänkatu 1",
    zip_code="00100",
    city="Helsinki",
    country_code="FI"
)

# Upload the paper mail attachment first
with open("letter.pdf", "rb") as f:
    attachment_id = client.upload_attachment("letter.pdf", f)

message_id, external_id = client.send_multichannel_message(
    title="Title",
    body="Hello, world!",
    body_format=BodyFormat.TEXT,  # or BodyFormat.MARKDOWN
    recipient_id="123456-789A",
    recipient_address=recipient_address,
    sender_address=sender_address,
    paper_mail_attachment_id=attachment_id,
)

All send methods return a (message_id, external_id) tuple:

  • message_id: the Suomi.fi identifier assigned to the message. Use this to reply to the message or to look it up via get_message().
  • external_id: your own identifier for the message, used for idempotency. If not provided, a UUID is generated automatically. Sending a message with the same external_id twice will raise SuomiFiDuplicateMessageError.

Sending an electronic message

Use this to send a new message or reply to a message from an end user:

message_id, external_id = client.send_electronic_message(
    title="Title",
    body="Hello, world!",
    body_format=BodyFormat.TEXT,
    recipient_id="123456-789A",
    reply_to=original_message_id,
    reply_allowed=True,
)

Sending paper mail without an identity code

Use this when the recipient's identity code is not known or not required. The recipient is identified solely by their postal address. Using the same Address setup as above:

with open("letter.pdf", "rb") as f:
    attachment_id = client.upload_attachment("letter.pdf", f)

message_id, external_id = client.send_paper_mail_without_id(
    recipient_address=recipient_address,
    sender_address=sender_address,
    attachment_id=attachment_id,
)

Reading events and messages

# Fetch events; pass continuation_token back in subsequent calls for pagination
events, continuation_token = client.get_events()
for event in events:
    message = client.get_message(event.metadata.message_id)
    # process message...

# Download an attachment from a received message
content = client.get_attachment(attachment_id)  # bytes

Error handling

from suomifi_messages import (
    SuomiFiAPIError,
    SuomiFiClientError,
    SuomiFiDuplicateMessageError,
    SuomiFiServerError,
)

try:
    message_id, external_id = client.send_electronic_message(...)
except SuomiFiDuplicateMessageError as e:
    # 409: message with this external_id already sent
    # e.message_id contains the original message ID
    existing_id = e.message_id
except SuomiFiClientError as e:
    # 4xx: bad request, mailbox not active, etc.
    print(e.response_body)
except SuomiFiServerError as e:
    # 5xx: retry later
    raise
except SuomiFiAPIError as e:
    # Unexpected non-2xx
    raise

The exception hierarchy is:

SuomiFiError
└── SuomiFiAPIError
    ├── SuomiFiClientError
    │   └── SuomiFiDuplicateMessageError
    └── SuomiFiServerError

For developers

Prerequisites

Testing

Run the tests with:

hatch test

Test all environments in the matrix with:

hatch test -a

Available Hatch scripts

Command Description Example
hatch run test <args> Run pytest directly hatch run test -k login
hatch run lint Install and run pre-commit hooks hatch run lint
hatch run manage <args> Run Django management commands hatch run manage migrate

Project details


Download files

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

Source Distribution

django_helsinki_suomifi_messages-1.0.0.tar.gz (26.9 kB view details)

Uploaded Source

Built Distribution

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

File details

Details for the file django_helsinki_suomifi_messages-1.0.0.tar.gz.

File metadata

File hashes

Hashes for django_helsinki_suomifi_messages-1.0.0.tar.gz
Algorithm Hash digest
SHA256 1e4d86f2e0da31db5d45535f8fd21265e09c3656e5f3e4a05ea155e88c15e811
MD5 122852e75106a5e6144c6d2fa3e51f9d
BLAKE2b-256 123e390cb18035409675caf5e123a688e433975005d2526d8327257eb550b633

See more details on using hashes here.

Provenance

The following attestation bundles were made for django_helsinki_suomifi_messages-1.0.0.tar.gz:

Publisher: publish.yml on City-of-Helsinki/django-helsinki-suomifi-messages

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

File details

Details for the file django_helsinki_suomifi_messages-1.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for django_helsinki_suomifi_messages-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 550c409eec3f06b6e2814d69822fddcec7942fa5806e2da65ec4561b65ff2e69
MD5 6f369018a563f8ab4ab107cc607cf2f0
BLAKE2b-256 7c1530b8e584f07aa1c2efe167046ec7dfa941a6b38735de2afd3c8c78a04602

See more details on using hashes here.

Provenance

The following attestation bundles were made for django_helsinki_suomifi_messages-1.0.0-py3-none-any.whl:

Publisher: publish.yml on City-of-Helsinki/django-helsinki-suomifi-messages

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

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page