Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,77 @@ digital_post.send_message("Digital Post", m, kombit_access)
The message module also contains a few static helper functions to construct simple messages. These are not meant to
be all encompassing but to help as a starting point.

## Physical mail

This library supports sending physical letters through the SF1601 Kombi API (Fjernprint).
The letter content is sent as a base64-encoded file (typically a PDF) along with recipient
address information.

### Fjernprint model

A data class model based on the official XSDs has been defined to help build the request payload.
The model is located in the physical_mail module:

```python
from python_serviceplatformen.models.physical_mail import ForsendelseI
```

**Note:** Like the MeMo model, the physical mail model doesn't follow the normal Python naming
conventions in order to stay close to the source XSD names.

### Send physical mail

To send a letter, construct a `ForsendelseI` object and pass it to `send_physical_mail`:

```python
import base64
import uuid

from python_serviceplatformen.authentication import KombitAccess
from python_serviceplatformen import digital_post
from python_serviceplatformen.models.physical_mail import (
AfsendelseIdentifikator, AfsendelseModtager, CountryIdentificationCode,
CountryIdentificationSchemeType, CPRnummerIdentifikator, DokumentParametre,
FilformatNavn, ForsendelseI, ForsendelseModtager, ForsendelseTypeIdentifikator,
MeddelelseIndholdData, ModtagerAdresse, PersonName, PostCodeIdentifier,
StreetBuildingIdentifier, StreetName, TransaktionsParametreI,
)

kombit_access = KombitAccess(cvr="55133018", cert_path=r"C:\somewhere\Certificate.pem")

with open("letter.pdf", "rb") as f:
pdf_bytes = f.read()

forsendelse = ForsendelseI(
afsendelse_identifikator=AfsendelseIdentifikator(value=str(uuid.uuid4())),
forsendelse_type_identifikator=ForsendelseTypeIdentifikator(value=265),
forsendelse_modtager=ForsendelseModtager(
afsendelse_modtager=AfsendelseModtager(
# Note that this should always be '0000000000' according to the documentation.
cpr_nummer_identifikator=CPRnummerIdentifikator(value="0000000000")
),
modtager_adresse=ModtagerAdresse(
person_name=PersonName(value="Test Testesen"),
street_name=StreetName(value="Testvej"),
street_building_identifier=StreetBuildingIdentifier(value="3"),
post_code_identifier=PostCodeIdentifier(value="2300"),
country_identification_code=CountryIdentificationCode(
value="DK",
scheme=CountryIdentificationSchemeType.ISO3166_ALPHA2,
),
),
),
filformat_navn=FilformatNavn(value="pdf"),
meddelelse_indhold_data=MeddelelseIndholdData(
value=base64.b64encode(pdf_bytes).decode()
),
transaktions_parametre_i=TransaktionsParametreI(),
dokument_parametre=DokumentParametre(),
)

transaction_id = digital_post.send_physical_mail(forsendelse, kombit_access)
```

## Beskedfordeler

This library supports retrieving messages from the Beskedfordeler using the AMQP BeskedHent service.
Expand Down
10 changes: 9 additions & 1 deletion changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [3.2.0] - 2026-06-16

### Added

- Models to describe physical mail (Fjernpost).
- Function to send physical mail.

## [3.1.0] - 2025-10-08

### Added
Expand Down Expand Up @@ -57,7 +64,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Module for authenticating towards Kombit's Serviceplatform API.
- Function for checking if someone is registered for Digital Post or NemSMS.

[Unreleased]: https://github.com/itk-dev-rpa/python-serviceplatformen/compare/3.1.0...HEAD
[Unreleased]: https://github.com/itk-dev-rpa/python-serviceplatformen/compare/3.2.0...HEAD
[3.2.0]: https://github.com/itk-dev-rpa/python-serviceplatformen/releases/tag/3.2.0
[3.1.0]: https://github.com/itk-dev-rpa/python-serviceplatformen/releases/tag/3.1.0
[3.0.1]: https://github.com/itk-dev-rpa/python-serviceplatformen/releases/tag/3.0.1
[3.0.0]: https://github.com/itk-dev-rpa/python-serviceplatformen/releases/tag/3.0.0
Expand Down
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "python_serviceplatformen"
version = "3.1.0"
version = "3.2.0"
authors = [
{ name="ITK Development", email="itk-rpa@mkb.aarhus.dk" },
]
Expand All @@ -20,6 +20,7 @@ dependencies = [
"cryptography",
"xmlschema",
"pika==1.3.*",
"xsdata"
]

[project.urls]
Expand Down
41 changes: 41 additions & 0 deletions python_serviceplatformen/digital_post.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,15 @@
from xml.etree import ElementTree

import requests
from xsdata.formats.dataclass.context import XmlContext
from xsdata.formats.dataclass.serializers import XmlSerializer
from xsdata.formats.dataclass.serializers.config import SerializerConfig

from python_serviceplatformen.authentication import KombitAccess
from python_serviceplatformen.date_helper import format_datetime
from python_serviceplatformen.models import xml_util
from python_serviceplatformen.models.message import Message
from python_serviceplatformen.models.physical_mail import ForsendelseI, ForsendelseISamling, KombiRequest


def is_registered(id_: str, service: Literal['digitalpost', 'nemsms'], kombit_access: KombitAccess) -> bool:
Expand Down Expand Up @@ -82,3 +86,40 @@ def send_message(message_type: Literal['Digital Post', 'NemSMS'],
response.raise_for_status()

return transaction_id


def send_physical_mail(forsendelse: ForsendelseI, kombit_access: KombitAccess) -> str:
"""Send a physical letter via the SF1601 Kombi API.

Args:
forsendelse: The ForsendelseI object describing the letter to send.
kombit_access: The KombitAccess object used to authenticate.

Returns:
The uuid of the transaction to trace the message later.
"""
url = urllib.parse.urljoin(kombit_access.environment, "service/KombiPostAfsend_1/kombi")

transaction_id = str(uuid.uuid4())

headers = {
"X-TransaktionsId": transaction_id,
"X-TransaktionsTid": format_datetime(datetime.now()),
"authorization": kombit_access.get_access_token("http://entityid.kombit.dk/service/kombipostafsend/1"),
"Content-Type": "application/xml"
}

serializer = XmlSerializer(
context=XmlContext(),
config=SerializerConfig(xml_declaration=False)
)
kombi_request = KombiRequest(
kombi_valg_kode="Fysisk Post",
forsendelse_i_samling=ForsendelseISamling(forsendelse_i=forsendelse),
)
xml_body = serializer.render(kombi_request)

response = requests.post(url=url, headers=headers, data=xml_body, cert=kombit_access.cert_path, timeout=10)
response.raise_for_status()

return transaction_id
Loading
Loading