Mail

Creating an e-mail using the novem python library

Before you beigin it’s important to have registered a novem account and installed the python library. See our python overview for details on how to get started.

Overview

This document will teach you how to create an e-mail using the novem python library.

Because the python library is just a wrapper on top of the existing novem http API there can often be several ways to achieve a goal. For this document we will however focus on the most pythonic ways of doing things.

It is however good to understand that under the hood, the python e-mail module will interact with the novem api, as such, even if you use a pythonic approach, the final result sent to the server will be a markdown document.

Getting started

The mail module exposes a novem Mail class that maps to the /v1/vis/mails/ api end-point.

The mail allows two primary way of constructing an e-mail. Either by supplying a novem markdown document as a content file or constructing the e-mail programatically.

Two styles

There are two primary ways to use the novem mail api, the markdown approach and the python approach. The markdown approach is very similar to the FUSE or CLI methods, where the e-mail is written as a markdown document and simply sent to the server.

The pythonic approach uses a lot more naitve python functionality and is what we’ll be using in this guide. We’ve included a couple of examples below to illustrate the difference.

The markdown appoarch

from novem import Mail

mail = Mail('name')                     # create mail object

mail.to = "user@example.com"            # add recipient

mail.subject = "Test e-mail"

mail.contet = """
{{ preview }}
Preview summary that is not visible in the main
body of the mail
{{ /preview }}

## Section title
---
Markdown text for text section
"""

mail.send()

The pythonic appoarch

from novem import Mail,
from novem.mail.sections import \
  PreviewSection, MarkdownSection
  

mail = Mail('name')                     # create mail object

mail.to = "user@example.com"            # add recipient

mail.subject = "Test e-mail"

mail.addSection(PreviewSection("""
Preview summary that is not visible in the main
body of the mail
"""))

mail.add_sectoin(MarkdownSection("""
## Section title
---
Markdown text for text section
"""
))

mail.send()

Viewing your mail

As with all novem visuals, e-mails can be previewed at the mails url. This is obtainable from the url property of the newly created e-mail object. Please note that if you’ve made changes to the e-mail you must call the render functions to update the web view.

from novem import Mail

mail = Mail('name')   # create mail object

mail.url              # https://novem.no/m/SHORTNAME

Mail

The primary way to interact with the novem mail in python is the novem Mail class. Similar to other novem classes the mail class exposes a set of attributes you can use to manipulate it. All attributes can also be supplied as named arguments to the constructor for ease of use.

The attributes maps to most of the endpoints listed on the mail overview page, put explicitly the following api endpoints are available as properties on the Mail class. Some properties are read only such as shortname and log whilst other, flagged with R below, will cause a full render of the e-mail (thus taking several seconds to run).

api path         : rw : type : R : class property
-----------------:----:------:---:---------------
email_name       :    :      :   : 
├── config       :    :      :   : 
│   ├── theme    : rw :  str : R : theme
│   ├── template : rw :  str : R : template
│   ├── size     : rw :  str : R : size
│   ├── reply_to : rw : bool :   : reply_to
│   └── subject  : rw :  str :   : subject
├── recipients   :    :      :   : 
│   ├── to       : rw :  str :   : to
│   ├── cc       : rw :  str :   : cc
│   └── bcc      : rw :  str :   : bcc
├── content      : rw :  str : R : content
├── status       : rw :  str :   : status
├── log          : r  :  str :   : log
├── url          : r  :  str :   : url
├── shortname    : r  :  str :   : shortname
├── description  : rw :  str :   : description
├── summary      : rw :  str :   : summary
└── name         : rw :  str :   : name

In addition to the above listed API mappings, there are some properties that are specific to the python only class such as id to get the id of the plot in addition to the common options such as sharing.

Attributes

Attributes are custom properties of the novem Mail object that will trigger actions when assigned. The attributes listed below are live and some of them will cause a re-render of the e-mail on the novem server.

Attributes can also be supplied as keyword arguments to the Mail constructor.

Theme

Render

Theme refers to the base color scheme used for the e-mail. By default all e-mails follows the novem color scheme, but for professional and higher subscriptions additional options might be available, including custom ones.

By default users can choose between:

  • novem - the default option which tries to automatically switch between light and dark mode.
  • novem-light - the light mode version of the default theme, does not adapt
  • novem-dark - the dark mode version of the default theme, does not adapt

To change the theme using the novem python API simply assign the relevant string value, updating this value will cause a rerender of the mail and may take some time.

from novem import Mail

# create a new mail
m = Mail("test_email")

# change theme
m.theme = "novem-dark"

# or alternatively
m = Mail("test_email", theme="novem-dark")
TODO: Reference api e-mail documentation for examples

Template

Render

Whilst the theme controls colors and various chart elements, template is for controlling larger layout changes. In particular header/footer aspects of the e-mail itself.

Similar to theme the default template is the standard novem template and only professional and above users have access to other e-mail templates.

Templates work similarly to other attributes and can be assigned as properties or constructor arguments.

TODO: Reference api e-mail documentation for examples

Size

Render

Size defines the maximum width of the e-mail content. Novem currently supports three size, small, medium and large. Small is targetted at mobile, medium is a compromise that should work both places and large is for desktop clients.

Valid values are s, m, l, small, medium or large.

TODO: Reference api e-mail documentation for examples

Subject

Subject line of the e-mail.

Recipients

Recipients encompass the recipients of the e-mail available as the to, cc and bcc properties. In addition the boolean property reply_to can be supplied to add a reply_to header referring to the registered and verified user e-mail address.

Please see the e-mail recipients section for details on address format and possible restrictions.

from novem import Mail

# create a new mail
m = Mail("test_email", 
  to = "novem_demo",  # set to and cc when creating the mail
  cc = "novem_test"
)

# update recipients, both strings and lists work
m.to = ["novem_demo", "novem_test"]

# as well as usernames and email addresses
m.cc = "novem_research; demo@example.com"  

Content

Render

Content is similar to the data endpoint of the plots in that it’s the primary information for the e-mail visualisations. The entire user controlled body of the e-mail is represented as a markdown document to be supplied to the content endpoint.

The content property, similar to plot data, can also be populated by invoking the mail object as a function.

from novem import Mail

# create a new mail
m = Mail("test_email")

with open("mail.md","r" as f:

  # set content directly
  m.content = f

  # or give content as the first argument  
  # of the class
  m(f)

Status

Render

The status endpoint represents the current state of the mail. By default the status will be draft, however if you want to send an email to the registered recipients you can change it to sent. If you want to do a test mail to yourself you can change it to test.

However, when using the python library we recommend using the explicit send and test functions instead as they will make sure the current segments are saved and the e-mail is updated before sending.

Utilities

We’ve classified the below attributes as utilities, they don’t directly affect the creation and the function of the e-mail, but they offer useful information.

Log

The log property is read only and will provide a newline delimited string of the current log for the mail. This can be useful if the mail doesn’t look as expected or some of the functions arent working.

Shortname

This property is read only and give you the current shortname of the plot.

Url

This property is read only and give you the current url of the plot.

Functions

Render

Render

If any sections have been added to the e-mail by calling add_section the render function will convert all the added sections into an novem advanced markdown document and write it to the server. This will update the web presentation and overwrite any existing data.

If no sections are added then invoking the render function will have no effect. If you want to write an empty string to the api please just assign it to the content attribute or call the mail object itself with the string.

from novem import Mail

# create a new mail
m = Mail("test_email")

# reset the novem mail content by assigning an empty string
m.content = ''

# or invoke the object with an empty string
m('')

Test

Render

The test funtion is created so you can send the e-mail to your own inbox. It will contain the assigned recipients, but will only be sent to your address. The address used is the registered and verified e-mail in your profile.

The subject will be prefixed with the string “TEST: “.

from novem import Mail

# create a new mail
m = Mail("test_email")

# to send a test e-mail, simply run the test function
m.test()

Send

Render

The send function operates identical to the test function above, except it will send the e-mail to all valid recipients.

from novem import Mail

# create a new mail
m = Mail("test_email")

# Send it 
m.send()

Sections

The sections api is offered to allow a more programatic approach to e-mail creation, offering specific and contextual names along with self documenting parameters.

Most sections directly map to the e-mail sections, but some are unique to the python library, (such as the markdown or code sections).

All sections must be added in the preferred display order using the Mail objects' add_section method.

Markdown

python only section

Markdown is the basic building block of the e-mail, this is how you add text, titles, lists and highlights. Markdown text is copied verbatim into the final content markdown document, so all instructions listed both under simple and advanced markdown in the novem markdown documentation can be used here.

The markdown object takes no paramters except the markdown text you want to display.

from novem import Mail
from novem.mail import MarkdownSection

# construct markdown section
ms = MarkdownSection("""
# A title

Followed by a paragraph

 * And
 * a
 * list

""")

# create a new mail
m = Mail("test_email")

# and finally, add the markdown section
m.add_section(ms)

Code

python only section

Code sections allows you to add syntax highlighted code to your e-mail, optional paramters are available to specify language.

from novem import Mail
from novem.mail import CodeSection

# Add a small code example in python
cs = CodeSection("""
# Create and send a simple novem mail
from novem import Mail

Mail("test", to="me")("Hello, World!").send()
""",
  lang="python",    # specify language to highlight
)

# create a new mail
m = Mail("test_email")

# and finally, add the code section
m.add_section(cs)

Preview

unique

Preview is a special class in that it’s not visible in the body of the e-mail. Instead, the text of the preview is only shown in the various e-mail client list views. This is useful for allowing a short summary of the e-mail content to be included in these list views, but not the e-mail itself.

There can only be one preview section in an e-mail and the novem api will use the last preivew section supplied.

The novem python library will take it one step further and assure there is only one preivew section present if you’re using the add_section api.

from novem import Mail
from novem.mail import PreviewSection

# Add preview section
ps = PreviewSection("""

""")

# create a new mail
m = Mail("test_email")

# and finally, add the preview
m.add_section(cs)

Visualisations

Visualisation sections map to the corresponding e-mail API sections, and as such, all the constructor arguments are mapped to the corresponding options. It’s strongly advised for the user to read the e-mail api reference, but for ease of use a short summary has been supplied below.

from novem import Plot, Mail
from novem.mail import VisSection

# grab a reference to a plot
plt = Plot("/u/novem_demo/p/state_pop")

# construct visualisation section
vss = VisSection(plt,       # a reference to the plot to include
  width="100%",             # width of plot in the context of the layout
  align="center",           # align the plot (relevant if less than 100%)
  include_title = False,    # include title of plot, if present
  include_caption = False,  # include caption of plot, if present
  include_link = False,     # include link to plot
  override_title = None,    # option to override title with text string
  override_caption = None   # option to override caption with text string
)

# create a new mail
m = Mail("test_email")

# and finally, add the vis section
m.add_section(vss)

Callouts

Callouts allows you to add a variety of highly visible notices in your e-mails. Currently there is support for warning, error, info and success.

In addition there is an optional border along with a small font descriptive text. For a full overview of callout options see the e-mail callout documentation.

The first argument to the callout class is the markdown encoded text of the callout message.

from novem import Mail
from novem.mail import CalloutSection

# Create callout section
cs = CalloutSection("""
Body text of the callout, simple markdown support.
""",
  type="warning",             # type of callout, default to info
  desc="Short description",   # optional small description
  border="dashed"             # border, solid, dashed or None
)

# create a new mail
m = Mail("test_email")

# and finally, add the callout section
m.add_section(cs)

Paragraph

Paragraphs allow you to add a whole section with custom formatting such as font-size, font-style, padding, margin and colors. In addition paragraph section can be used with an empty content to create custom padding and margin in your novem mail.

By default the paragraph section takes font_size and font_style as custom arguments along with the common section arguments, for a full overview of paragraph options see the e-mail paragraph documentation.

from novem import Mail
from novem.mail import ParagraphSection 

# Create paragraph example
ps = ParagraphSection("""
One or more markdown paragraphs of disclaimer text goes here.
""",
  m = ["t3", "b3"],  # margin top and bottom
  font_size= "s",    # small font size
  font_style= "i",   # italic
  fg = "gray-500"    # in soft gray
)

# create a new mail
m = Mail("test_email")

# and finally, add the paragraph section
m.add_section(ps)

Author

Author sections allows you to embed an author section containing an optional image along with name and a small biography. The author takes a novem username as a mandatory option.

The author section will by default populate name, bio and picture from the profile of the user depending on user settings. There are further restrictoins which can be found in the e-mail author documentation.

from novem import Mail
from novem.mail import AuthorSection

# Create author example
ats = AuthorSection("@novem_demo",                # username to fetch data for
  include_bio = True,                             # include small bio
  override_bio = ( "Novem demo is the standard"   # override conten of bio
  "novem demo account used to create **simple** "
  "illustrations and examples."),
  include_picture: True                           # include user picture
)

# create a new mail
m = Mail("test_email")

# and finally, add the author section
m.add_section(ats)

Attachments

Attachments allows you to add other novem visuals as attachment to your e-mail. The most common would be PDF versions of plots, grids and docs, but novem also has csv and excel versions of both input and output data available.

For more details on novem attachments see the e-mail attachments documentation and the api file output documentation.

from novem import Plot, Mail
from novem.mail import AttachmentSection

# grab a reference to a plot
plt = Plot("/u/novem_demo/p/state_pop")

# construct attachment section
ats = VisSection(plt,       # a reference to the plot to include
  file = "plot.pdf",        # select the pdf version
  override_name = "top US state populations.pdf" # rename the file
)

# create a new mail
m = Mail("test_email")

# and finally, add the attachment section
m.add_section(ats)

Examples

TODO: add e-mail example urls TODO: design e-mail embed

Complete example

from novem import Mail, Plot

from novem.mail import VisSection\ 
MarkdownSection, AuthorSection, CalloutSection, \
PaddingSection


# Creat a new novem e-mail

m = Mail('novem_email_test',
 to = 'me',
 cc = '@novem_test',
 subject = 'Daily test mail',
 layout = 'standard',
 width = 'medium'
)

mail.preview = """
Here comes the preview text, thisis not visible in the body of the em-mail
"""


m.addSectoion(CalloutSection("""
Callout markdown content
""",
  kind="warning"
  pre="Description text",
  border="dashed bold"
)


m.addSection(MarkdownSection("""
## Simple markdown header

Some markdown text
"""),
title="Special section title",
sep = 'line'
)

# add a test plot
m.addSection(
  VisSection(Plot('novem_test_lot')),
  include_caption = True,
  include_title = True
)


# add some more text
m.addSection(MarkdownSection("""
## Simple markdown header

Some markdown text
"""),
title="Special section title",
sep = 'line'
)
  
m.addSection(AuthorSection(
  description="Novem Test is a novem test account."
  username="@novem_test",
  name="Novem Test Account",
  img=True,
))

m.save()

m.test()

m.send()