7. Email APIs

This document describes the nprstuff email API, which provides the lower-level back-end functionality for rest_email. These modules live in nprstuff.npremail.

The main module implements a bunch of different things

  • validating and converting reStructuredText strings to rich HTML.

  • doing stuff with Imgur credentials.

  • doing stuff with Google OAuth2 authentication to services that will send email, and get google contacts, using Google’s APIs.

  • A single convenience widget, HtmlView, that acts as a rudimentary browser that can display rich HTML.

class nprstuff.npremail.HtmlView(parent, htmlString='')

A convenient PyQt5 widget that displays rich and interactive HTML (HTML with CSS and Javascript). This extends QWebEngineView. This defines new actions, with shortcuts, to move forward one page, backward one page, or reset.

Parameters:
  • parent – the controlling QWidget, if any.

  • htmlString (str) – the input initial rich HTML.

Variables:

initHTMLString (str) – this widget has the ability to reset to the initial HTML web page used to construct it. This attribute stores that rich HTML as a string.

reset()

Reverts to the initial website.

waitUntilReady()

A subordinate process that loads all website elements (CSS and Javascript) until done.

nprstuff.npremail.check_imgurl_credentials(clientID, clientSECRET, clientREFRESHTOKEN, verify=True)

validate the Imgur API credentials with the provided API client ID, secret, and refresh token.

Parameters:
  • clientID (str) – the Imgur client ID.

  • clientSECRET (str) – the Imgur client secret.

  • clientREFRESHTOKEN (str) – the Imgur client refresh token.

  • verify (bool) – optional argument, whether to verify SSL connections. Default is True.

Returns:

whether the new credentials are correct.

Return type:

bool

nprstuff.npremail.format_size(fsize_b)

Formats the bytes value into a string with KiB, MiB or GiB units. This code has been copied from deluge's format_size.

Parameters:

fsize_b (int) – the filesize in bytes.

Returns:

formatted string in KiB, MiB or GiB units.

Return type:

str

Usage

>>> format_size( 112245 )
'109.6 KiB'
nprstuff.npremail.get_imgurl_credentials()

retrieves the Imgur API credentials from the SQLite3 configuration database.

Returns:

a dict of the Imgur API credentials. Its structure is,

{ 'clientID': XXXX,
  'clientSECRET': XXXX,
  'clientREFRESHTOKEN': XXXX,
  'mainALBUMID': XXXX,
  'mainALBUMTITLE': XXXX }
Return type:

dict

nprstuff.npremail.md5sum(filename)

Taken from This StackOverflow on how to calculate the MD5 sum of a file.

Parameters:

filename (str) – the candidate file’s name to open.

Returns:

an MD5 hash of the file.

Return type:

str

nprstuff.npremail.oauthGetGoogleCredentials(verify=True)

Gets the Google Oauth2 credentials, stored in the SQLite3 configuration database, in the form of a refreshed Credentials object. This OAuth2 authentication method is used for ALL the services accessed by NPRStuff.

Parameters:

verify (bool) – optional argument, whether to verify SSL connections. Default is True.

Returns:

a Credentials form of the Google Oauth2 credentials for various OAuth2 services.

Return type:

Credentials

nprstuff.npremail.oauth_generate_google_permission_url()

Generates a Google OAuth2 web-based flow for all the Google services used in NPRStuff. The authentication process that uses this flow is described in this subsection. Here are the programmatic steps to finally generate an Credentials object.

  1. Get the Flow and authentication URI.

    flow, auth_uri = oauth_generate_google_permission_url( )
    
  2. Go to the URL, auth_uri, in a browser, grant permissions, and copy the authorization code in the browser window. This authorization code is referred to as authorization_code.

  3. Create the Credentials using authorization_code.

    fetch_token( code = authorization_code )
    credentials = flow.credentials
    
Returns:

a tuple of two elements. The first element is a Flow web server flow object. The second element is the redirection URI string that redirects the user to begin the authorization flow.

Return type:

tuple

See also

nprstuff.npremail.oauth_store_google_credentials(credentials)

Store the form of a Credentials object, as a JSON string, into the SQLite3 configuration database.

Parameters:

credentials – the Credentials object to store into the database.

See also

nprstuff.npremail.store_imgurl_credentials(clientID, clientSECRET, clientREFRESHTOKEN, verify=True, mainALBUMID=None, mainALBUMNAME=None)

stores the Imgur API credentials into the SQLite3 configuration database.

Parameters:
  • clientID (str) – the Imgur client ID.

  • clientSECRET (str) – the Imgur client secret.

  • clientREFRESHTOKEN (str) – the Imgur client refresh token.

  • verify (bool) – optional argument, whether to verify SSL connections. Default is True.

  • mainALBUMID (str) – optional argument. If given, then store this album hash into the database.

  • mainALBUMNAME (str) – optional argument. If given, then store this album hash into the database.

Returns:

the string "SUCCESS" if could store the new Imgur credentials. Otherwise, the string 'ERROR, COULD NOT STORE IMGURL CREDENTIALS.'.

Return type:

str

7.1. email module

This module contains common utilities to retrieve contacts, craft email, and send email. This module lives in nprstuff.npremail.npremail.

nprstuff.npremail.npremail.get_all_email_contacts_dict(verify=True, people_service=None, pagesize=4000)

Returns all the Google contacts using the Google Contacts API.

Parameters:
  • verify (bool) – optional argument, whether to verify SSL connections. Default is True.

  • people_service – optional argument, the Resource representing the Google people service used to retrieve one’s Google contacts. If None, then generated here.

  • pagesize (int) – optional argument, the maximum number of candidate contacts to search through. Must be \(\ge 1\).

Returns:

a dict of contacts. The key is the contact name, and the value is the set of email addresses for that contact.

Return type:

dict

nprstuff.npremail.npremail.get_email_service(verify=True, credentials=None)

This returns a working Resource representing the Google email service used to send and receive emails.

Parameters:

verify (bool) – optional argument, whether to verify SSL connections. Default is True.

Returns:

the Resource representing the Google email service used to send and receive emails.

Return type:

Resource

nprstuff.npremail.npremail.get_people_service(verify=True, credentials=None)

This returns a working Resource representing the Google people service used to get a list of one’s Google contacts.

Parameters:

verify (bool) – optional argument, whether to verify SSL connections. Default is True.

Returns:

the Resource representing the Google people service.

Return type:

Resource

nprstuff.npremail.npremail.send_collective_email_full(mainHTML, subject, fromEmail, to_emails, cc_emails, bcc_emails, verify=True, email_service=None, attachments=[])

Sends the HTML email to the following TO recipients, CC recipients, and BCC recipients altogether. It uses the GMail API.

Parameters:
  • mainHTML (str) – the email body as an HTML string document.

  • subject (str) – the email subject.

  • fromEmail (str) – the RFC 2047 sender’s email with name.

  • to_emails (set) – the RFC 2047 set of TO recipients.

  • cc_emails (set) – the RFC 2047 set of CC recipients.

  • bcc_emails (set) – the RFC 2047 set of BCC recipients.

  • verify (bool) – optional argument, whether to verify SSL connections. Default is True.

  • email_service – optional argument, the Resource representing the Google email service used to send and receive emails. If None, then generated here.

  • attachments (list) – the collection of attachments to send out.

nprstuff.npremail.npremail.send_email_lowlevel(msg, email_service=None, verify=True)

Sends out an email using the Google Contacts API. If process is unsuccessfull, prints out an error message, "problem with <TO-EMAIL>", where <TO-EMAIL> is the recipient’s email address.

Parameters:
  • msg (MIMEMultiPart) – the MIMEMultiPart email message to send. At a high level, this is an email with body, sender, recipients, and optional attachments.

  • email_service – optional argument, the Resource representing the Google email service used to send and receive emails. If None, then generated here.

  • verify (bool) – optional argument, whether to verify SSL connections. Default is True.

  • userId (str) – The user ID to send email as, using the Google Mail API. Can be an RFC 2047 sender’s email with name, but default is me. See this page for info on method signature.

See also

get_email_service.

nprstuff.npremail.npremail.send_individual_email_full(mainHTML, subject, emailAddress, name=None, attach=None, attachName=None, attachType='txt', verify=True, email_service=None)

Sends the HTML email, with optional single attachment, to a single recipient email address, using the GMail API. Unlike send_individual_email_full_withsingleattach, the attachment type is also set.

Parameters:
  • mainHTML (str) – the email body as an HTML str document.

  • subject (str) – the email subject.

  • emailAddress (str) – the recipient email address.

  • name (str) – optional argument. If given, the recipient’s name.

  • mydate (date) – optional argument. The date at which the email is sent. Default is now( ).

  • attach (str) – optional argument. If defined, the Base64 encoded attachment.

  • attachName (str) – optional argument. The list of attachment names, if there is an attachment. If defined, then attachData must also be defined.

  • attachType (str) – the attachment type. Default is txt.

  • verify (bool) – optional argument, whether to verify SSL connections. Default is True.

  • email_service – optional argument, the Resource representing the Google email service used to send and receive emails. If None, then generated here.

7.2. email_imgur module

This module hooks into the Imgur account, and the albums and images in albums, that it contains. It also implements widgets in rest_email that manipulate the images in one’s Imgur album. This module lives in nprstuff.npremail.email_imgur.

class nprstuff.npremail.email_imgur.NPRStuffIMGClient(verify=True, data_imgurl=None)

This object contains and implements the collection of images located in a single main album in the Imgur account. This uses the Imgur API to peform all operations. This object is constructed using Imgur credentials – the client ID, secret, and refresh token – stored in the SQLite3 configuration database, and stores the following attributes: the client ID, secret, refresh token, and the access token used for API access to your Imgur album and images.

If the Imgur albums cannot be accessed, or there are no albums, then self.albumID = None, the self.imgHashes is an empty dict.

The main album ID is stored as a string in the Imgur configuration under the mainALBUMID key, if it exists; otherwise the Imgur configuration dictionary does not have a mainALBUMID key.

  • If there is no main album ID defined, or if there is no album with that ID, then we choose the first album found, and reset the Imgur configuration data into the SQLite3 database with this album ID and name.

  • If the configured album exists in our Imgur library, then continue with this the main album.

Once the main album is found, populate self.imghashes with all the pictures in this album. The pictures in an album in our Imgur account are expected to be filled through methods in this object.

  • The key is the MD5 hash of the image in that library.

  • The value is a four element tuple: image name, image ID, the URL link to this image, and the datetime at which the image was uploaded.

Parameters:
  • verify (bool) – optional argument, whether to verify SSL connections. Default is True.

  • data_imgurl (dict) – optional argument. If defined, must have the following keys: clientID, clientSECRET, and clientREFRESHTOKEN. Must be consistent with dict returned by get_imgurl_credentials.

Variables:
  • verify (bool) – whether to verify SSL connections.

  • access_token (str) – the persistent API access token to the user’s Imgur account.

  • clientID (str) – the Imgur client ID.

  • clientSECRET (str) – the Imgur client secret.

  • albumID (str) – the hashed name of the main album.

  • imghashes (dict) – the structure of images stored in the main album.

Raises:

ValueError – if images in the new album cannot be accessed.

See also

refreshImages.

change_album_name(new_album_name)

Changes the main album name to a new name, only if the new name is different from the old name.

Parameters:

new_album_name (str) – the new name to change the main Imgur album.

See also

refreshImages.

change_name(imgMD5, new_name)

Changes the name of an image in the main Imgur library.

Parameters:
  • imgMD5 (str) – this is the MD5 hash of the image in the main Imgur library.

  • new_name (str) – the new name to give this image.

Returns:

True if image could be found and its name changed. Otherwise returns False.

Return type:

bool

delete_candidate_album(candidate_album_name)

This deletes the candidate album from the Imgur account. This album with that name must exist in the Imgur account.

Parameters:

candidate_album_name (str) – the name of the album to remove, with its underlying images.

See also

refreshImages.

delete_image(b64img, imgMD5=None)

Removes an image from the main Imgur library.

Parameters:
  • b64img (str) – the Base64 representation of the image.

  • imgMD5 (str) – optional argument. This is the MD5 hash of the image. If not provided, this is calculated for that image represented by b64img.

Returns:

True if image can be found and returned. Otherwise returns False.

Return type:

bool

get_candidate_album_names()
Returns:

a list of album names in the Imgur account. set_main_album can use this method to determine the valid album name to choose.

See also

get_candidate_albums.

get_candidate_albums()
Returns:

a dict of album information, organized by album name. Each key in the top-level dictionary is the album name. Each value is a lower level dictionary: the id key is the album ID, and the images key is a list of low-level Imgur image information.

classmethod get_image_md5(image)
Returns:

the MD5 hash of the image.

Parameters:

image (PngImageFile) – the native Pillow PNG image object.

get_main_album_name()
Returns:

the name of the main Imgur album, if albums exist on this account. Otherwise returns None.

Return type:

str

refreshImages()

Refreshes the collection of images in the main Imgur album, by filling out self.imghashes. The pictures in an album in our Imgur account are expected to be filled through methods in this object.

  • The key is the MD5 hash of the image in that library.

  • The value is a four element tuple: image name, image ID, the URL link to this image, and the datetime at which the image was uploaded.

set_main_album(new_album_name)

Sets or changes the main Imgur album used for storing and displaying images to a new album name. If new_album_name exists in the Imgur account, then sets that name. If new_album_name does not exist, then creates this new Imgur album.

Once this album is set or created,

  • sets the new Imgur credentials using store_imgur_credentials.

  • populates self.imghashes with all the images found in this library. If the album does not exist, then self.imghashes is an empty dict.

Parameters:

new_album_name (str) – the new name of the Imgur album to use for images.

Raises:

ValueError – if images in the new album cannot be accessed.

See also

refreshImages.

upload_image(b64img, name, imgMD5=None)

Uploads a Base64 encoded file into the main Imgur album. If the image exists, then returns information (from self.imghashes) about the file. If not, create it, put it into self.imghashes, and then return its information.

Parameters:
  • b64img (str) – the Base64 representation of the image.

  • name (str) – name of the image.

  • imgMD5 (str) – optional argument. This is the MD5 hash of the image. If not provided, this is calculated for that image represented by b64img.

Returns:

a 4-element tuple: image name, image ID, the URL link to this image, and the datetime at which the image was uploaded.

Return type:

tuple

class nprstuff.npremail.email_imgur.PNGPicDelegate
createEditor(self, parent: QWidget, option: QStyleOptionViewItem, index: QModelIndex) QWidget
setEditorData(self, editor: QWidget, index: QModelIndex)
class nprstuff.npremail.email_imgur.PNGPicLabel(img, parent=None)

This class that extends QLabel follows advice from this StackOverflow article. This object also generates its own QPixMap from the QImage it keepts.

Parameters:
  • img – the QImage of the PNG image either loaded from a file or from Imgur.

  • parent – the parent QWidget, if defined, and for which this widget is a child.

Variables:

img – the source QImage used to regenerate its own background QPixMap.

hasHeightForWidth(self) bool
heightForWidth(width)

This method is slotted to one of the resize events, and is defined to fix the aspect ratio of the source QImage

Parameters:

width (int) – the width passed on a resizing event for this widget.

resizeEvent(evt)

On resize, regenerates its own background QPixMap with the same aspect ratio as its source QImage, but with the widget’s new width.

Parameters:

evt – the resizing QEvent.

class nprstuff.npremail.email_imgur.PNGPicObject(initdata, pImgClient)

This provides a GUI widget to the Imgur interface implemented in PlexIMGClient. Initializaton of the image can either upload this image to the Imgur account, or retrieve the image from the main Imgur album. This object can also launch a GUI dialog window through getInfoGUI.

Parameters:
  • initdata (dict) –

    the low-level dictionary that contains important information on the image, located in a file, that will either be uploaded into the main Imgur album or merely kept in memory. The main key that determines operation is initialization. It can be one of "FILE" or "SERVER".

    If initialization is "FILE", then upload the the image to the main album in the Imgur account. Here are the required keys in initdata.

    • filename is the location of the image file on disk.

    • actName is the PNG filename to be used. It must end in png.

    If initialization is "SERVER", then retrieve this image from the main album in the Imgur account. Here are the required keys in initdata.

    • imgurlink is the URL link to the image.

    • imgName is the name of the image.

    • imgMD5 is the MD5 hash of the image.

    • imgDateTime is the datetime at which the image was initially uploaded into the main Imgur album.

  • pImgClient (PlexIMGClient) – the PlexIMGClient used to access and manipulate (add, delete, rename) images in the main Imgur album.

Variables:
  • actName (str) – the file name without full path, which must end in png.

  • img (QImage) – the QImage representation of this image.

  • originalImage (Image) – the Image representation of this image.

  • originalWidth (float) – the inferred width in cm.

  • currentWidth (float) – the current image width in cm. It starts off as equal to originalWidth

  • b64string (str) – the Base64 encoded representation of this image as a PNG file.

  • imgurlLink (str) – the URL link to the image.

  • imgDateTime (datetime) – the datetime at which this image was first uploaded to the main album in the Imgur account.

Raises:

ValueError – if initdata['initialization'] is neither "FILE" nor "SERVER".

b64String()
Returns:

a 3-element tuple on the image incorporated into this object: its Base64 string, its width in pixels, and the Imgur link.

Return type:

tuple

changeName(new_name, nImgClient)

changes the filename into a new name.

Parameters:
  • new_name (str) – the new name of the image file to be changed in the main album on the Imgur account. This must end in png.

  • nImgClient (NPRStuffIMGClient) – the NPRStuffIMGClient used to access and manipulate (add, delete, rename) images in the main Imgur album.

classmethod createPNGPicObjects(pImgClient)
Parameters:

pImgClient (PlexIMGClient) – the PlexIMGClient used to access and manipulate (add, delete, rename) images in the main Imgur album.

Returns:

a list of PNGPicObject representing the images in the main Imgur album.

Return type:

list

getInfoGUI(parent)

Launches a QDialog that contains the underlying image and some other labels: ACTNAME is the actual PNG file name, URL is the image’s Imgur link, and UPLOADED AT is the date and time at which the file was uploaded. An example image is shown below,

_images/email_pngpicobject_infogui.png

Fig. 7.1 An example PNG image that can be stored in the main Imgur library. Note the three rows above the image: the name of the PNG image; its URL; and the date and time it was uploaded.

Parameters:

parent (QWidget) – the parent QWidget that acts as the QDialog window’s parent. Can be None.

class nprstuff.npremail.email_imgur.PNGPicQSortFilterModel(model)
filterAcceptsRow(self, source_row: int, source_parent: QModelIndex) bool
class nprstuff.npremail.email_imgur.PNGPicTableModel(parent)
columnCount(self, parent: QModelIndex = QModelIndex()) int
data(self, index: QModelIndex, role: int = Qt.ItemDataRole.DisplayRole) Any
flags(self, index: QModelIndex) Qt.ItemFlags
headerData(self, section: int, orientation: Qt.Orientation, role: int = Qt.ItemDataRole.DisplayRole) Any
rowCount(self, parent: QModelIndex = QModelIndex()) int
setData(self, index: QModelIndex, value: Any, role: int = Qt.ItemDataRole.EditRole) bool
sort(self, column: int, order: Qt.SortOrder = Qt.AscendingOrder)
class nprstuff.npremail.email_imgur.PNGPicTableView(parent)
contextMenuEvent(self, a0: QContextMenuEvent)
resizeEvent(self, e: QResizeEvent)
class nprstuff.npremail.email_imgur.PNGWidget(parent)