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