Python API

Exchange

class RPA.Email.Exchange.Exchange(vault_name: Optional[str] = None, vault_token_key: Optional[str] = None, tenant: Optional[str] = None)

Exchange is a library for sending, reading, and deleting emails. Exchange is interfacing with Exchange Web Services (EWS).

For more information about server settings, see this Microsoft support article.

Examples

Robot Framework

*** Settings ***
Library     RPA.Email.Exchange
...     vault_name=email_oauth_microsoft    vault_token_key=token
...     tenant=ztzvn.onmicrosoft.com  # your custom tenant here
Task Setup      Ensure Auth

*** Variables ***
${ACCOUNT}              ACCOUNT_NAME
${RECIPIENT_ADDRESS}    RECIPIENT
${IMAGES}               myimage.png
${ATTACHMENTS}          C:${/}files${/}mydocument.pdf

*** Keywords ***
Ensure Auth
    ${secrets} =    Get Secret    email_oauth_microsoft
    RPA.Email.Exchange.Authorize    ${ACCOUNT}
    ...    is_oauth=${True}  # use the OAuth2 auth code flow (required)
    ...    client_id=${secrets}[client_id]  # app ID
    ...    client_secret=${secrets}[client_secret]  # app password
    ...    token=${secrets}[token]  # token dict (access, refresh, scope etc.)

*** Tasks ***
Task of sending email
    Send Message  recipients=${RECIPIENT_ADDRESS}
    ...           subject=Exchange Message from RPA Robot
    ...           body=<p>Exchange RPA Robot message body<br><img src='myimage.png'/></p>
    ...           save=${TRUE}
    ...           html=${TRUE}
    ...           images=${IMAGES}
    ...           cc=EMAIL_ADDRESS
    ...           bcc=EMAIL_ADDRESS
    ...           attachments=${ATTACHMENTS}

Task of listing messages
    # Attachments are saved specifically with a keyword Save Attachments
    ${messages}=    List Messages
    FOR    ${msg}    IN    @{messages}
        Log Many    ${msg}
        ${attachments}=    Run Keyword If    "${msg}[subject]"=="about my orders"
        ...    Save Attachments
        ...    ${msg}
        ...    save_dir=${CURDIR}${/}savedir
    END
    # Using save_dir all attachments in listed messages are saved
    ${messages}=    List Messages
    ...    INBOX/Problems/sub1
    ...    criterion=subject:'about my orders'
    ...    save_dir=${CURDIR}${/}savedir2
    FOR    ${msg}    IN    @{messages}
        Log Many    ${msg}
    END

Task of moving messages
    Move Messages    criterion=subject:'about my orders'
    ...    source=INBOX/Processed Purchase Invoices/sub2
    ...    target=INBOX/Problems/sub1

Python

from RPA.Email.Exchange import Exchange
from RPA.Robocorp.Vault import Vault

vault_name = "email_oauth_microsoft"
secrets = Vault().get_secret(vault_name)
ex_account = "ACCOUNT_NAME"

mail = Exchange(
    vault_name=vault_name,
    vault_token_key="token",
    tenant="ztzvn.onmicrosoft.com"
)
mail.authorize(
    username=ex_account,
    is_oauth=True,
    client_id=secrets["client_id"],
    client_secret=secrets["client_secret"],
    token=secrets["token"]
)
mail.send_message(
    recipients="RECIPIENT",
    subject="Message from RPA Python",
    body="RPA Python message body",
)

OAuth2

The OAuth2 flow is the only way of authorizing at the moment as Microsoft disabled entirely the usage of passwords, even App Passwords. And since you have to work with tokens now and because this library has the capability to automatically refresh an expired token, please don’t forget to initialize the library with the following parameters: vault_name, vault_token_key and tenant.

Learn more on how to use the OAuth2 flow in this Portal robot example-oauth-email.

About criterion parameter

Following table shows possible criterion keys that can be used to filter emails. There apply to all keywords which have criterion parameter.

Key

Effective search

subject

subject to match

subject_contains

subject to contain

body

body to match

body_contains

body to contain

sender

sender (from) to match

sender_contains

sender (from) to contain

before

received time before this time

after

received time after this time

between

received time between start and end

category

categories to match

category_contains

categories to contain

importance

importance to match

Keys before, after and between at the moment support two different timeformats either %d-%m-%Y %H:%M or %d-%m-%Y. These keys also support special string NOW which can be used especially together with keyword Wait for message  criterion=after:NOW.

When giving time which includes hours and minutes then the whole time string needs to be enclosed into single quotes.

before:25-02-2022
after:NOW
between:'31-12-2021 23:50 and 01-01-2022 00:10'

Different criterion keys can be combined.

subject_contains:'new year' between:'31-12-2021 23:50 and 01-01-2022 00:10'

Please note that all values in the criterion that contain spaces need to be enclosed within single quotes.

In the following example the email subject is going to matched only against new not new year.

subject_contains:new year
ROBOT_LIBRARY_DOC_FORMAT = 'REST'
ROBOT_LIBRARY_SCOPE = 'GLOBAL'
TO_PROTECT = ['authorize', 'get_oauth_token', 'refresh_oauth_token']
authorize(username: str, password: Optional[str] = None, autodiscover: bool = True, access_type: Union[AccessType, str] = AccessType.DELEGATE, server: Optional[str] = None, primary_smtp_address: Optional[str] = None, is_oauth: bool = False, client_id: Optional[str] = None, client_secret: Optional[str] = None, token: Optional[dict] = None) None

Connect to Exchange account

Parameters
  • username – account username

  • password – account password (can be skipped with OAuth2)

  • autodiscover – use autodiscover or set it off (on by default)

  • access_type – default “DELEGATE”, other option “IMPERSONATION”

  • server – required for configuration setting (with autodiscover off)

  • primary_smtp_address – by default set to username, but can be set to be different from username

  • is_oauth – use the OAuth2 authorization code flow (instead of basic auth)

  • client_id – registered application ID

  • client_secret – registered application secret (password)

  • token – contains access and refresh tokens, type, scope, expiry etc.

create_folder(folder_name: str, parent_folder: Optional[str] = None)

Create email folder.

Parameters
  • folder_name – name for the new folder (required)

  • parent_folder – name for the parent folder, by default INBOX

delete_folder(folder_name: str, parent_folder: Optional[str] = None)

Delete email folder.

Parameters
  • folder_name – current folder name (required)

  • parent_folder – name for the parent folder, by default INBOX

delete_message(message: Dict)

Delete message.

Parameters

message – dictionary containing message details

empty_folder(folder_name: str, parent_folder: Optional[str] = None, delete_sub_folders: Optional[bool] = False)

Empty email folder of all items

Parameters
  • folder_name – current folder name (required)

  • parent_folder – name for the parent folder, by default INBOX

  • delete_sub_folders – delete sub folders or not, by default False

Returns

True if operation was successful, False if not

forward_message(message: Dict, recipients: Union[str, List])

Forward message.

Parameters
  • message – dictionary containing message details

  • recipients – email address or list of email addresses

generate_oauth_url(client_id: str) str

Generates an authorization URL which must be opened by the user to start the OAuth2 flow and obtain an authorization code as response.

Parameters

client_id – Client app ID. (generated by the provider)

Returns

Authorization URL string not containing any sensitive info in it.

Example: Robot Framework

*** Tasks ***
Start OAuth Flow
    ${auth_url} =    Generate OAuth URL
    ...     client_id=810482312368-19htmcgcj*******googleusercontent.com
    Log     Start OAuth2 flow: ${auth_url}
get_oauth_token(client_secret: str, response_url: str) dict

Exchanges the code obtained previously with Generate OAuth URL for a token.

Parameters
  • client_secret – Client app secret. (generated by the provider)

  • response_url – The final URL containing the authorization code found in the address bar after authenticating and authorizing the Client app through the authorization URL.

Returns

A dictionary containing the access & refresh token, plus metadata.

Example: Robot Framework

*** Tasks ***
Finish OAuth Flow
    ${token} =      Get OAuth Token
    ...     client_secret=GOCSPX-******mqZAW89
    ...     response_url=${resp_url}  # redirect of `Generate OAuth URL`
list_messages(folder_name: Optional[str] = None, criterion: Optional[str] = None, contains: Optional[bool] = False, count: Optional[int] = 100, save_dir: Optional[str] = None, items_only: Optional[bool] = False) list

List messages in the account inbox. Order by descending received time.

Parameters
  • folder_name – name of the email folder, default INBOX

  • criterion – list messages matching criterion

  • contains – if matching should be done using contains matching and not equals matching, default False is means equals matching

  • count – number of messages to list

  • save_dir – set to path where attachments should be saved, default None (attachments are not saved)

  • items_only – return only list of Message objects (instead of dictionaries)

list_unread_messages(folder_name: Optional[str] = None, criterion: Optional[str] = None, contains: Optional[bool] = False, count: Optional[int] = 100, save_dir: Optional[str] = None) list

List unread messages in the account inbox. Order by descending received time.

Parameters
  • folder_name – name of the email folder, default INBOX

  • criterion – list messages matching criterion

  • contains – if matching should be done using contains matching and not equals matching, default False is means equals matching

  • count – number of messages to list

  • save_dir – set to path where attachments should be saved, default None (attachments are not saved)

move_message(msg: Optional[dict], target: Optional[str])

Move a message into target folder

Parameters
  • msg – dictionary of the message

  • target – path to target folder

Raises

AttributeError – if msg is not a dictionary containing id and changekey attributes

Example:

${messages}=    List Messages
...    INBOX
...    criterion=subject:about my orders
FOR    ${msg}    IN    @{messages}
    Run Keyword If    "${msg}[sender][email_address]"=="${priority_account}"
    ...    Move Message    ${msg}    target=INBOX / Problems / priority
END
move_messages(criterion: Optional[str] = '', source: Optional[str] = None, target: Optional[str] = None, contains: Optional[bool] = False) bool

Move message(s) from source folder to target folder

Parameters
  • criterion – move messages matching this criterion

  • source – source folder

  • target – target folder

  • contains – if matching should be done using contains matching and not equals matching, default False is means equals matching

Returns

boolean result of operation, True if 1+ items were moved else False

Criterion examples:

  • subject:my message subject

  • body:something in body

  • sender:sender@domain.com

refresh_oauth_token(client_id: str, client_secret: str, token: dict) dict

Refreshes the token as the access one usually expires after 1h and the refresh one never expires. (as long as it doesn’t get revoked)

Parameters
  • client_id – Client app ID. (generated by the provider)

  • client_secret – Client app secret. (generated by the provider)

  • token – Full token dictionary previously obtained with Get OAuth Token.

Returns

A token dictionary containing a new access token and updated metadata.

Example: Robot Framework

*** Tasks ***
Refresh OAuth Flow
    ${token} =      Refresh OAuth Token
    ...     client_id=810482312368-19htmcgcj*******googleusercontent.com
    ...     client_secret=GOCSPX-******mqZAW89
    ...     token=${token}  # from `Get OAuth Token`
rename_folder(oldname: str, newname: str, parent_folder: Optional[str] = None)

Rename email folder

Parameters
  • oldname – current folder name

  • newname – new name for the folder

  • parent_folder – name for the parent folder, by default INBOX

Returns

True if operation was successful, False if not

save_attachments(message: Union[dict, str], save_dir: Optional[str] = None, attachments_from_emls: bool = False, overwrite: bool = False) list

Save attachments from message into given directory.

Parameters
  • message – dictionary or .eml file path containing message details

  • save_dir – file path where attachments will be saved

  • attachments_from_emls – pass True if the attachment is an EML file (for saving attachments from that EML file instead), False otherwise (default)

  • overwrite – overwrite existing downloaded attachments with the same name if set to True, False otherwise (default)

Returns

list of saved attachments

Example:

${messages} =    List Messages
FOR    ${msg}    IN    @{messages}
    Save Attachments    ${msg}    %{ROBOT_ARTIFACTS}
    ...    attachments_from_emls=${True}
END

${attachments} =    Save Attachments    ${CURDIR}${/}saved.eml
...    %{ROBOT_ARTIFACTS}    overwrite=${True}
save_message(message: dict, filename: str)

Save email as .eml file.

Parameters
  • message – dictionary containing message details

  • filename – name of the file to save message into

send_message(recipients: Optional[Union[List[str], str]] = None, subject: Optional[str] = '', body: Optional[str] = '', attachments: Optional[Union[List[str], str]] = None, html: Optional[bool] = False, images: Optional[Union[List[str], str]] = None, cc: Optional[Union[List[str], str]] = None, bcc: Optional[Union[List[str], str]] = None, save: Optional[bool] = False, reply_to: Optional[str] = None) None

Keyword for sending message through connected Exchange account.

Parameters
  • recipients – list of email addresses

  • subject – message subject, defaults to “”

  • body – message body, defaults to “”

  • attachments – list of filepaths to attach, defaults to None

  • html – if message content is in HTML, default False

  • images – list of filepaths for inline use, defaults to None

  • cc – list of email addresses

  • bcc – list of email addresses

  • save – is sent message saved to Sent messages folder or not, defaults to False

  • reply_to – email address to reply to

Email addresses can be prefixed with ex: to indicate an Exchange account address.

At least one target needs to exist for recipients, cc or bcc.

send_reply_message(message: Union[Message, str], body: str, subject: Optional[str] = None, reply_all: bool = False)

Send reply to a message.

Parameters
  • message – either Message object or ID of the message for the message which this is replying to

  • body – message body for the reply

  • subject – optional subject for the reply, defaults to None

  • reply_all – if True then reply is sent to all recipients, defaults to False

Robot Framework example

${messages}=    List Messages    criterion=subject:'I have new query'
FOR    ${m}    IN    @{messages}
    # Verifying that this is email that I want to reply to
    ${now}=    RPA.Calendar.Time Now   UTC  return_format=YYYY-MM-DD HH:mm
    ${received}=    Evaluate    str($m["datetime_received"])
    ${diff}=   RPA.Calendar.Time Difference In Minutes   ${received}  ${now}
    # message was received less than 5 minutes
    # and it came from the expected address
    IF    $diff < 5 and "${m}[sender]" == "mika@robocorp.com"
        Send Reply Message
        ...  ${m}[id]
        ...  body=I totally agree
    END
END
wait_for_message(criterion: Optional[str] = '', timeout: Optional[float] = 5.0, interval: Optional[float] = 1.0, contains: Optional[bool] = False, save_dir: Optional[str] = None) Any

Wait for email matching criterion to arrive into INBOX.

Parameters
  • criterion – wait for message matching criterion

  • timeout – total time in seconds to wait for email, defaults to 5.0

  • interval – time in seconds for new check, defaults to 1.0 (minimum)

  • contains – if matching should be done using contains matching and not equals matching, default False is means equals matching THIS PARAMETER IS DEPRECATED AS OF rpaframework 12.9.0

  • save_dir – set to path where attachments should be saved, default None (attachments are not saved)

Returns

list of messages