ACE (Automated Communications Engine) is a framework for automatically sending messages to users.
edx_ace
exports the typical set of functions and classes needed to use
ACE.
Bases: object
Channels deliver messages to users that have already passed through the presentation and policy steps.
Examples include email messages, push notifications, or in-browser messages. Implementations of this abstract class should not require any parameters be passed into their constructor since they are instantiated.
channel_type
must be a ChannelType
.
Transmit a rendered message to a recipient.
Validate settings to determine whether this channel can be enabled.
Returns true if this channel specifically wants to handle this message, outside normal channel delivery rules.
For example, say you use a django transactional email channel, but with a default channel of braze. Then if the braze channel is configured with a campaign for a certain transactional message id specifically, it will claim that message via this method and end up delivering it via braze instead of the normal transactional django channel.
Bases: Enum
All supported communication channels.
Bases: MessageAttributeSerializationMixin
A Message
is the core piece of data that is passed into ACE.
It captures the message, recipient, and all context needed to render
the message for delivery.
app_label (str) – The name of the Django app that is sending this message. Used to look up the appropriate template during rendering. Required.
name (str) – The name of this type of message. Used to look up the appropriate template during rendering. Required.
recipient (Recipient
) – The intended recipient of the
message. Optional.
expiration_time (datetime
) – The date and time
at which this message expires. After this time, the message
should not be delivered. Optional.
context (dict) – A dictionary to be supplied to the template at render time as the context.
send_uuid (uuid.UUID
) – The uuid.UUID
assigned
to this bulk-send of many messages.
language (str) – The language the message should be rendered in. Optional.
logger (logging.Logger
) – The logger to be adapted.
Returns: MessageLoggingAdapter
that is specific to this message.
The identity of this message for logging.
A unique name for this message, used for logging and reporting.
Returns: str
Bases: MessageAttributeSerializationMixin
A class representing a type of Message
. An instance of
a MessageType
is used for each batch send of messages.
context (dict) – Context to be supplied to all messages sent in this batch of messages.
expiration_time (datetime.datetime
) – The time at which
these messages expire.
app_label (str) – Override the Django app that is used to resolve
the template for rendering. Defaults to APP_LABEL
or
to the app that the message type was defined in.
name (str) – Override the message name that is used to resolve
the template for rendering. Defaults to NAME
or
to the name of the class.
Get default app Label.
Return default class name.
Bases: object
A Policy
allows an application to specify what Channel
any specific
Message
shouldn’t be sent over. Policies are one of the primary
extension mechanisms for ACE, and are registered using the entrypoint openedx.ace.policy
.
Validate the supplied Message
against a specific
delivery policy.
message (Message
) – The message to run the policy against.
PolicyResult
A PolicyResult
that represents what channels the message
should not be delivered over.
Bases: object
deny (set) – A set of ChannelType
values that should be excluded
when sending a message.
Bases: MessageAttributeSerializationMixin
The target for a message.
Bases: object
This class represents a pattern for separating the content of a message
(the MessageType
) from the selection of recipients (the RecipientResolver
).
send()
a Message
personalized from msg_type
to all
recipients selected by this RecipientResolver
.
msg_type (MessageType
) – An instantiated MessageType
that describes the message batch to send.
Send a message to a recipient.
Calling this method will result in an attempt being made to deliver the provided message to the recipient. Depending on the configured policies, it may be transmitted to them over one or more channels (email, sms, push etc).
The message must have valid values for all required fields in order for it to be sent. Different channels have
different requirements, so care must be taken to ensure that all of the needed information is present in the message
before calling ace.send()
.
msg (Message) – The message to send.
The main entry point for sending messages with ACE.
Usage:
from edx_ace import ace
from edx_ace.messages import Message
msg = Message(
name="test_message",
app_label="my_app",
recipient=Recipient(lms_user_id='123456', email='a_user@example.com'),
language='en',
context={
'stuff': 'to personalize the message',
}
)
ace.send(msg)
Send a message to a recipient.
Calling this method will result in an attempt being made to deliver the provided message to the recipient. Depending on the configured policies, it may be transmitted to them over one or more channels (email, sms, push etc).
The message must have valid values for all required fields in order for it to be sent. Different channels have
different requirements, so care must be taken to ensure that all of the needed information is present in the message
before calling ace.send()
.
msg (Message) – The message to send.
edx_ace.channel
exposes the ACE extension point needed
to add new delivery Channel
instances to an ACE application.
Developers wanting to add a new deliver channel should subclass Channel
,
and then add an entry to the openedx.ace.channel
entrypoint in their setup.py
.
Bases: object
Channels deliver messages to users that have already passed through the presentation and policy steps.
Examples include email messages, push notifications, or in-browser messages. Implementations of this abstract class should not require any parameters be passed into their constructor since they are instantiated.
channel_type
must be a ChannelType
.
Transmit a rendered message to a recipient.
Validate settings to determine whether this channel can be enabled.
Returns true if this channel specifically wants to handle this message, outside normal channel delivery rules.
For example, say you use a django transactional email channel, but with a default channel of braze. Then if the braze channel is configured with a campaign for a certain transactional message id specifically, it will claim that message via this method and end up delivering it via braze instead of the normal transactional django channel.
Bases: object
A class that represents a channel map, usually as described in Django settings and setup.py files.
Gets a registered a channel by its name and type.
Returns the first registered channel by type.
UnsupportedChannelError – If there’s no channel that matched the request.
channel_type (ChannelType) – The channel type.
Bases: Enum
All supported communication channels.
Gathers all available channels.
Note that this function loads all available channels from entry points. It expects the Django setting
ACE_ENABLED_CHANNELS
to be a list of plugin names that should be enabled. Only one plugin per channel type
should appear in that list.
ValueError – If multiple plugins are enabled for the same channel type.
A mapping of channel types to instances of channel objects that can be used to deliver messages.
Based on available channels() returns a single channels for a message.
UnsupportedChannelError – If there’s no channel matches the request.
The selected channel object.
edx_ace.channel.sailthru
implements a SailThru-based email delivery
channel for ACE.
Bases: IntEnum
These error codes are present in responses to requests that can (and should) be retried after waiting for a bit.
Something’s gone wrong on Sailthru’s end. Your request was probably not saved - try waiting a moment and trying again.
Bases: Enum
These are special headers returned in responses from the Sailthru REST API.
Bases: Channel
An email channel for delivering messages to users using Sailthru.
This channel makes use of the Sailthru REST API to send messages. It is designed for “at most once” delivery of messages. It will make a reasonable attempt to deliver the message and give up if it can’t. It also only confirms that Sailthru has received the request to send the email, it doesn’t actually confirm that it made it to the recipient.
The integration with Sailthru requires several Django settings to be defined.
Example
Sample settings:
.. settings_start
ACE_CHANNEL_SAILTHRU_DEBUG = False
ACE_CHANNEL_SAILTHRU_TEMPLATE_NAME = "Some template name"
ACE_CHANNEL_SAILTHRU_API_KEY = "1234567890"
ACE_CHANNEL_SAILTHRU_API_SECRET = "this is secret"
.. settings_end
The named template in Sailthru should be minimal, most of the rendering happens within ACE. The “From Name” field
should be set to {{ace_template_from_name}}
. The “Subject” field should be set to {{ace_template_subject}}
.
The “Code” for the template should be:
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
{{ace_template_head_html}}
</head>
<body>
{body_html = replace(ace_template_body_html, '{view_url}', view_url)}
{body_html = replace(body_html, '{optout_confirm_url}', optout_confirm_url)}
{body_html = replace(body_html, '{forward_url}', forward_url)}
{body_html = replace(body_html, '{beacon_src}', beacon_src)}
{body_html}
<span id="sailthru-message-id" style="display: none;">{message_id()}</span>
<a href="{optout_confirm_url}" style="display: none;"></a>
</body>
</html>
This method is now deprecated in favor of get_action_links, but will continue to work for the time being as it calls get_action_links under the hood.
Transmit a rendered message to a recipient.
Returns: True iff all required settings are not empty and the Sailthru client library is installed.
Provides list of action links, called by templates directly. Supported kwargs:
omit_unsubscribe_link (bool): Removes the unsubscribe link from the email. DO NOT send emails with no unsubscribe link unless you are sure it will not violate the CANSPAM act.
Provides list of trackers, called by templates directly
edx_ace.channel.django_email
implements a Django send_mail() email
delivery channel for ACE.
Bases: EmailChannelMixin
, Channel
A send_mail() channel for edX ACE.
This is both useful for providing an alternative to Sailthru and to debug ACE mail by inspecting django.core.mail.outbox.
Example
Sample settings:
.. settings_start
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'localhost'
DEFAULT_FROM_EMAIL = 'hello@example.org'
ACE_CHANNEL_DEFAULT_EMAIL = 'sailthru_email'
ACE_CHANNEL_TRANSACTIONAL_EMAIL = 'django_email'
ACE_ENABLED_CHANNELS = [
'sailthru_email',
'django_email',
]
.. settings_end
Transmit a rendered message to a recipient.
Returns: True always!
edx_ace.errors
exposes all exceptions that are specific to ACE.
Bases: Exception
Indicates something went wrong in a delivery channel.
Bases: ChannelError
A fatal error occurred during channel delivery. Do not retry.
Bases: Exception
Encountered a message that cannot be sent due to missing or inconsistent information.
Bases: ChannelError
An error occurred during channel delivery that is non-fatal. The caller should re-attempt at a later time.
Bases: ChannelError
Raised when an attempt is made to process a message for an unsupported channel.
edx_ace.message
contains the core Message
and MessageType
classes, which allow specification of the content to be delivered by ACE.
Bases: MessageAttributeSerializationMixin
A Message
is the core piece of data that is passed into ACE.
It captures the message, recipient, and all context needed to render
the message for delivery.
app_label (str) – The name of the Django app that is sending this message. Used to look up the appropriate template during rendering. Required.
name (str) – The name of this type of message. Used to look up the appropriate template during rendering. Required.
recipient (Recipient
) – The intended recipient of the
message. Optional.
expiration_time (datetime
) – The date and time
at which this message expires. After this time, the message
should not be delivered. Optional.
context (dict) – A dictionary to be supplied to the template at render time as the context.
send_uuid (uuid.UUID
) – The uuid.UUID
assigned
to this bulk-send of many messages.
language (str) – The language the message should be rendered in. Optional.
logger (logging.Logger
) – The logger to be adapted.
Returns: MessageLoggingAdapter
that is specific to this message.
The identity of this message for logging.
A unique name for this message, used for logging and reporting.
Returns: str
Bases: LoggerAdapter
A logging.LoggingAdapter
that prefixes log items with
a message log_id
.ABCMeta
Expects a message
key in its extra
argument which should
contain the Message
being logged for.
Delegate a debug call to the underlying logger.
Process the logging message and keyword arguments passed in to a logging call to insert contextual information. You can either manipulate the message itself, the keyword args or both. Return the message and kwargs modified (or not) to suit your needs.
Normally, you’ll only need to override this one method in a LoggerAdapter subclass for your specific needs.
Bases: MessageAttributeSerializationMixin
A class representing a type of Message
. An instance of
a MessageType
is used for each batch send of messages.
context (dict) – Context to be supplied to all messages sent in this batch of messages.
expiration_time (datetime.datetime
) – The time at which
these messages expire.
app_label (str) – Override the Django app that is used to resolve
the template for rendering. Defaults to APP_LABEL
or
to the app that the message type was defined in.
name (str) – Override the message name that is used to resolve
the template for rendering. Defaults to NAME
or
to the name of the class.
Get default app Label.
Return default class name.
edx_ace.monitoring
exposes functions that are useful for reporting ACE
message delivery stats to monitoring services.
edx_ace.policy
contains all classes relating to message policies.
These policies manage which messages should be sent over which channels, and are a point of pluggability in ACE.
Bases: object
A Policy
allows an application to specify what Channel
any specific
Message
shouldn’t be sent over. Policies are one of the primary
extension mechanisms for ACE, and are registered using the entrypoint openedx.ace.policy
.
Validate the supplied Message
against a specific
delivery policy.
message (Message
) – The message to run the policy against.
PolicyResult
A PolicyResult
that represents what channels the message
should not be delivered over.
Bases: object
deny (set) – A set of ChannelType
values that should be excluded
when sending a message.
message (Message
) – The message apply policies to.
A set of ChannelType
values that are allowed by all policies
applied to the message.
edx_ace.renderers
contains the classes used by ACE to
render messages for particular types of delivery channels. Each
ChannelType
has a distinct subclass of AbstractRenderer
associated with it, which is used to render messages for all
Channel
subclasses of that type.
Bases: object
Base class for message renderers.
A message renderer is responsible for taking one, or more, templates, and context, and outputting a rendered message for a specific message channel (e.g. email, SMS, push notification).
message (Message
) – The message being rendered.
filename (str) – The basename of the template file to look up.
The full template path to the template to render.
Renders the given message.
channel (Channel
) – The channel to render the message for.
message – The message being rendered.
Bases: AbstractRenderer
A renderer for ChannelType.EMAIL
channels.
alias of RenderedEmail
Bases: object
Encapsulates all values needed to send a Message
over an ChannelType.EMAIL
.
An internal module that manages the presentation/rendering step of the ACE pipeline.
Returns the rendered content for the given channel and message.
edx_ace.recipient
contains Recipient
, which captures all targeting
information needed to deliver a message to some user.
Bases: MessageAttributeSerializationMixin
The target for a message.
edx_ace.recipient_resolver
contains the RecipientResolver
, which facilitates
a design pattern that separates message content from recipient lists.
Bases: object
This class represents a pattern for separating the content of a message
(the MessageType
) from the selection of recipients (the RecipientResolver
).
send()
a Message
personalized from msg_type
to all
recipients selected by this RecipientResolver
.
msg_type (MessageType
) – An instantiated MessageType
that describes the message batch to send.
edx_ace.serialization
contains MessageAttributeSerializationMixin
,
which allows messages to be round-tripped through JSON, and
MessageEncoder
, which actually performs the JSON encoding.
Bases: object
This mixin allows an object to be serialized to (and deserialized from) a JSON string.
__str__()
and from_string()
function as inverses,
and are the primary point of interaction with this mixin by
outside clients.
to_json()
is used to recursively convert the object to a
python dictionary that can then be encoded to a JSON string.
Decode a JSON-encoded string representation of this type.
string_value (str) – The JSON string to decode.
An instance of this class.
a python dictionary containing all serializable fields of this object, suitable for JSON-encoding.
Bases: JSONEncoder
Custom Message Encoder.
Implement this method in a subclass such that it returns
a serializable object for o
, or calls the base implementation
(to raise a TypeError
).
For example, to support arbitrary iterators, you could implement default like this:
def default(self, o):
try:
iterable = iter(o)
except TypeError:
pass
else:
return list(iterable)
# Let the base class default method raise the TypeError
return JSONEncoder.default(self, o)
edx_ace.utils.date
contains utility functions used for
serializing and deserializing dates. It is intended for internal ACE
use.
Deserialize a datetime object from an ISO8601 formatted string.
timestamp_iso8601_str (basestring) – A timestamp as an ISO8601 formatted string.
A timezone-aware python datetime object.
datetime
The current time in the UTC timezone as a timezone-aware datetime object.
Serialize a datetime object to an ISO8601 formatted string.
timestamp_obj (datetime) – The timestamp to serialize.
A string representation of the timestamp in ISO8601 format.
basestring
edx_ace.utils.once
provides the ability to create a module-level
function that caches it’s result after the first call (this can be used
for lazy-loading expensive computations).
Decorates a function that will be called exactly once.
After the function is called once, its result is stored in memory and immediately returned to subsequent callers instead of calling the decorated function again.
Examples
An incrementing value:
_counter = 0
@once
def get_counter():
global _counter
_counter += 1
return _counter
def get_counter_updating():
global _counter
_counter += 1
return _counter
print(get_counter()) # This will print "0"
print(get_counter_updating()) # This will print "1"
print(get_counter()) # This will also print "0"
print(get_counter_updating()) # This will print "2"
Lazy loading:
@once
def load_config():
with open('config.json', 'r') as cfg_file:
return json.load(cfg_file)
cfg = load_config() # This will do the relatively expensive operation to
# read the file from disk.
cfg2 = load_config() # This call will not reload the file from disk, it
# will use the value returned by the first invocation
# of this function.
func (callable) – The function that should be called exactly once.
The wrapped function.
callable
edx_ace.utils.plugins
contains utility functions used
to make working with the ACE plugin system easier. These are intended
for internal use by ACE.
Check the extension to see if it’s enabled.
extension (stevedore.extension.Extension) – The extension to check.
namespace (basestring) – The namespace that the extension was loaded from.
names (list) – A whitelist of extensions that should be checked.
Whether or not this extension is enabled and should be used.
Get the stevedore extension manager for this namespace.
namespace (basestring) – The entry point namespace to load plugins for.
names (list) – A list of names to load. If this is None
then all extension will be loaded from this
namespace.
Extension manager with all extensions instantiated.
stevedore.enabled.EnabledExtensionManager
Get all extensions for this namespace and list of names.
Test utilities.
Since pytest discourages putting __init__.py into test directory (i.e. making tests a package) one cannot import from anywhere under tests folder. However, some utility classes/methods might be useful in multiple test modules (i.e. factoryboy factories, base test classes). So this package is the place to put them.
Bases: Policy
Short term policy.
Validate the supplied Message
against a specific
delivery policy.
message (Message
) – The message to run the policy against.
PolicyResult
A PolicyResult
that represents what channels the message
should not be delivered over.
Set active policies for the duration of a test.
test_case (unittest.TestCase
) – The test case that is running
policies – The set of active policies to return from edx_ace.policy.policies()
Functions for delivering ACE messages.
This is an internal interface used by ace.send()
.
Deliver a message via a particular channel.
.UnsupportedChannelError – If no channel of the requested channel type is available.