Sending Secure Messages

One of the most common asks we get is how to send a secure message to an end user from the SDK. What we recommend is using the Q2API’s SendSecureMessageAsXML endpoint. We recommend this one because it is the most robust and configurable messaging endpoint and also offers attachment support for your messages

Note

There are several Q2API endpoints for secure messaging and you may not need all the features of this one. Feel free to use any of the other ones if they suit your needs better

One very important thing to note is that, unlike the other Q2API endpoints, this one only has one parameter other than logger, a fully formatted XML string. Building XML by hand is frustrating even for experienced developers. Luckily for everyone, we have a built-in helper to construct this XML string

class q2_sdk.hq.api_helpers.build_secure_message_xml(source_id, target_id, message_subject, message_body, sender_type='Administrator', target_type='AdministratorGroup', creation_time=None, expiration_time=None, attachment=None)[source]

Builds an xml_payload for use with HQ’s SendSecureMessageAsXML

Parameters:
  • source_id (int) – “from” group id

  • target_id (int) – recipient ID

  • message_subject (str) – Subject of the secure message

  • message_body (str) – Body of the secure message

  • sender_type (Optional[SecureMessengerType]) – Optional choice from SecureMessengerType. Defaults to Administrator

  • target_type (Optional[SecureMessengerType]) – Optional choice from SecureMessengerType. Defaults to AdministratorGroup

  • creation_time (Optional[datetime]) – Time message was generated

  • expiration_time (Optional[datetime]) – Timestamp at which message will expire

  • attachment (Optional[SecureMessageAttachment]) – Optional choice from SecureMessageAttachment.

Returns:

Already escaped xml_payload

Building XML by hand is frustrating even for experienced developers, especially when having to navigate the intricacies of the Q2 System.

Note

The ids you need refer to different entities depending on the SecureMessengerType:

  • For AdminGroup, the ids refer to entries in the Q2_MessageRecipientGroup table and can be accessed using the matching db object

  • For EndUser, the ids refer to entries in the Q2_User table and can be accessed using the matching db object

  • For Administrator, the ids refer to entries in the Q2_AdminUsers table. There’s no matching db object for this, but if you know the admin login name, you can get their admin_id via the UserLogon DbObject

Below is a fully functional code snippet and the import statements to send a secure message with an attachment. It shows an example message with how to open and add a file as an attachment as well as how to get target_id and source_id programmatically using db objects

import os
from datetime import datetime, timedelta
from q2_sdk.hq.api_helpers import build_secure_message_xml
from q2_sdk.hq.models.secure_messenger_type import SecureMessengerType
from q2_sdk.hq.models.secure_message_attachment import SecureMessageAttachment
from q2_sdk.hq.hq_api.q2_api import SendSecureMessageAsXml


async def default(self):
    # Init db objects
    # Returns a list of users that match the criteria. Only one has login retail0
    # Use whatever identifier you want to find the customer
    user_id = (await self.db.user.get(login_name='retail0'))[0].UserID
    message_group_id = (await self.db.message_recipient_group.get_by_name("Customer Service")).GroupID

    directory = os.path.dirname(os.path.realpath(__file__))  # Get directory where this python code is located
    path = os.path.join(directory, 'file.txt')  # Change this to wherever you want to load your file from
    with open(path, 'rb') as file:
        data = file.read()
    attachment = SecureMessageAttachment("file.txt", data)

    ## NOTE:
    # Some of these parameters are passed as positional (user_id) while others
    # are passed as a keyword (creation_time=)
    # In Python, it's normally possible to do either, but the convention is to pass
    # parameters that have defaults in the underlying function as a keyword, which required
    # parameters are passed as positional. The build_secure_message_xml function here takes
    # 4 required parameters, then the rest are optional. As such, we pass the first 4 as
    # positional, then define the keyword variant on the remainder.
    xml_str = build_secure_message_xml(
        message_group_id,  # source_id
        user_id,  # target_id
        'TestXMLBuilder',  # message_subject
        'Message Body',  # message_body
        sender_type=SecureMessengerType.AdministratorGroup,
        target_type=SecureMessengerType.EndUser,
        creation_time=datetime.now(),
        expiration_time=datetime.now()+timedelta(7),
        attachment=attachment
    )

    params = SendSecureMessageAsXml.ParamsObj(self.logger, xml_str, hq_credentials=self.hq_credentials)
    await SendSecureMessageAsXml.execute(params)
    return "Success"