# How to test email and SMS in Python Learn how to automate testing of email and SMS messages in Python, using Mailosaur. ## 1. Create a Mailosaur account If you already have an account, skip to step 2. To create a new trial account, [sign up here](/app/signup). ## 2. Create a sample project ### Install Python To see if you already have Python installed, open a terminal window and run this command: ```bash python --version ``` If Python is installed, you’ll see a version number. If you see an error instead, then [download Python](https://www.python.org/downloads) and install it. ### Create a new project Run each of these commands to create a new folder for your Python project: ```bash mkdir EmailTests cd EmailTests ``` ### Install the Mailosaur Python library Run this command to install the [Mailosaur Python package](https://github.com/mailosaur/mailosaur-python): ```bash pip install mailosaur ``` ## 3. Send email to your Mailosaur inbox Inboxes allow you to group tests, permissions, and other settings together. Each inbox has an **Inbox ID** and a **domain name**. You need these values to both send email to Mailosaur, and to set up automated testing. You also need an [API key](/docs/managing-your-account/api-keys) to use. You can learn more about [creating API keys here](/docs/managing-your-account/api-keys). ### Retrieve your inbox’s attributes 1. In the left-hand navigation, locate the **Inboxes** section. 2. Click on the name of the inbox you want to test with. 3. Click on the **API** tab. 4. Make a note of the **Inbox ID**, **domain name** and **API key**. ### Send an email to your inbox If the **domain name** of your inbox above was: ```bash example.mailosaur.net ``` Then you can send an email to it with these steps: 1. Open up an email client and send an email to `anything@example.mailosaur.net` 2. In the left-hand navigation, locate the **Inboxes** section. 3. Click on the name of the inbox you sent an email to. 4. Confirm the email is there. Note that some services (like Gmail) may take 10-20 seconds to send a message through. To learn more, read our guide on [sending email to Mailosaur](/docs/email-testing/sending-to-mailosaur). ## 4. Find an email for automated testing Now that you have a sample project, your inbox’s credentials, and an email to test, then you’re ready to continue. Create a file named `hello.py` and type or paste in this code sample, replacing the template code with the values from step 3 above: ```python from mailosaur import MailosaurClient from mailosaur.models import SearchCriteria # Available in the API tab of an inbox api_key = "YOUR_API_KEY" server_id = "SERVER_ID" server_domain = "SERVER_DOMAIN" mailosaur = MailosaurClient(api_key) criteria = SearchCriteria() criteria.sent_to = "anything@" + server_domain email = mailosaur.messages.get(server_id, criteria) print("Subject: " + email.subject) ``` This code connects to Mailosaur and looks for any email that has been sent to the address provided in the search criteria. Save your changes and run the code: ```bash python hello.py ``` If everything is set up correctly, you should see the subject line of the last email you sent, printed to screen: ```bash Subject: My example email ``` ### Troubleshooting If you see an error, e.g. ‘No matching messages found in time’: - Make sure you have set the **sent to** address correctly in your code. - Ensure that you have sent an email to the **sent to** address (check this is visible in the Mailosaur Dashboard). - Note that by default, the **get** method will only look for messages that were received by Mailosaur within the last hour. You can override this using the `received_after` option (see library reference below). ## 5. Narrowing your search results ### Only find messages received after a certain time By default, searches include messages received in the last hour, but you can customise the search window with the `received_after` option. This example shows you how to only include emails received after your test started: ```python test_start = datetime.today() - timedelta(minutes=1) # Perform the steps that send a message here criteria = SearchCriteria() criteria.sent_to = "..." message = mailosaur.messages.get("SERVER_ID", criteria, received_after=test_start) ``` ### Search criteria As you can see in the examples so far, you can search for the email address or phone number a message was sent to, but you can also search using these criteria: | PARAMETER | DESCRIPTION | | ------------ | ------------ | | **sent_from** | The full email address from which the target message was sent. | | **sent_to** | The full email address to which the target message was sent. | | **subject** | Find emails where the subject line contains this text. | | **body** | Finds messages where the message body contains this text. | ## 6. Start writing tests Now that you have a working project that fetches an email, you can use this to begin writing tests for various pieces of functionality. Check out these guides on the most common test cases: > [!LINK](/docs/automation/text-content) > ### How to test the text content of email or SMS > Learn how to test the text content of email or SMS with Mailosaur. > [!LINK](/docs/automation/html-content) > ### HTML content of an email > Learn how to work with the HTML content found within your emails. > [!LINK](/docs/automation/codes) > ### Extracting codes from email and SMS > Learn how to test verification codes found in email and SMS messages with Mailosaur. > [!LINK](/docs/automation/links) > ### Extracting links from email and SMS > Learn how to test hyperlinks found in email and SMS messages with Mailosaur. > [!LINK](/docs/automation/attachments) > ### Email attachments > Learn how to test the email attachments with Mailosaur. > [!LINK](/docs/automation/images) > ### Images and web beacons > Learn how to work with images, including web beacons, within an HTML email. > [!LINK](/docs/automation/message-properties) > ### Message properties > Learn how to test the common properties of an email or SMS message with Mailosaur. > [!LINK](/docs/automation/spam) > ### How to test email spam score > Learn how to test the SpamAssassin score of an email with Mailosaur. ## SMS Testing You can test SMS messages in much the same way as email. Take a look at our [guide on testing SMS messages](/docs/sms-testing) for more information. ## Library reference The Python client library gives you access to several other methods. ### Messages Messages is the collective name given to the email and/or SMS messages that are sent into Mailosaur for testing. The [message object](/docs/api) contains everything you need to perform in-depth automated testing. #### messages.get(server, criteria, options) Waits for a message to be found. Returns as soon as a message matching the specified search criteria is found. **Recommended:** This is the most efficient method of looking up a message, therefore we recommend using it wherever possible. ```python criteria = SearchCriteria() criteria.sent_to = "someone@SERVER_ID.mailosaur.net" message = mailosaur.messages.get("SERVER_ID", criteria) ``` To learn about inbox IDs, and what to replace `SERVER_ID` with, see [sending email to Mailosaur](/docs/email-testing/sending-to-mailosaur). ##### Criteria | PARAMETER | DESCRIPTION | | ------------ | ------------ | | **sent_from** | The full email address from which the target message was sent. | | **sent_to** | The full email address to which the target message was sent. | | **subject** | The subject line of the target email. | | **body** | Search for part of the message body. | | **match** | If set to `ALL` (default), then only results that match all specified criteria will be returned. If set to `ANY`, results that match any of the specified criteria will be returned. | ##### Options | PARAMETER | DESCRIPTION | | ------------ | ------------ | | **timeout** | Specify how long to wait for a matching result (in milliseconds, _default value is 10 seconds_). | | **received_after** | Limits results to only messages received after this date/time (_default 1 hour ago_). | ```python from datetime import datetime, timedelta # ... criteria = SearchCriteria() criteria.sent_to = "someone@SERVER_ID.mailosaur.net" ten_minutes_ago = datetime.today() - timedelta(minutes=10) # Search all messages received in the last 10 minutes mailosaur.messages.get("SERVER_ID", criteria, received_after=ten_minutes_ago) ``` #### messages.list(server, options) Returns a list of your messages in summary form. The summaries are returned sorted by received date, with the most recently-received messages appearing first. > [!SUCCESS] > The method returns a message summary, rather than the full message object. This means that several properties, like the message body, are not included. To get this data, you’ll need to call [`get_by_id`](#messagesget_by_idid). Alternatively, we recommend using the [`get`](#messagesgetserver-criteria-options) method, which is a far more efficient approach. ```python # List the most recent messages result = mailosaur.messages.list('SERVER_ID') # Get the most recent message (the first one in the list) message = result.items[0] print('Subject: ' + message.subject) ``` ##### Options - **received_after** Allows you to customise how far back to look for messages. - **page** Used alongside `items_per_page` to paginate through results. This is zero-based, meaning `0` is the first page of results. - **items_per_page** A limit on the number of results to be returned. This can be set between 1 to 1000, with the default being 50. ```python from datetime import datetime, timedelta # ... ten_minutes_ago = datetime.today() - timedelta(minutes=10) # List all results received in the last 10 minutes result = mailosaur.messages.list('SERVER_ID', page=0, items_per_page=10, received_after=ten_minutes_ago) ``` #### messages.search(server, criteria, options) Returns a list of messages matching the specified search criteria, in summary form. The messages are returned sorted by received date, with the most recently-received messages appearing first. > [!SUCCESS] > The method returns a message summary, rather than the full message object. This means that several properties, like the message body, are not included. To get this data, you’ll need to call [`get_by_id`](#messagesget_by_idid). Alternatively, we recommend using the [`get`](#messagesgetserver-criteria-options) method, which is a far more efficient approach. ```python from mailosaur.models import SearchCriteria # ... criteria = SearchCriteria() criteria.sent_to = "someone@SERVER_ID.mailosaur.net" result = mailosaur.messages.search('SERVER_ID', criteria) # Get the most recent match message = result.items[0] print('Subject: ' + message.subject) ``` ##### Criteria | PARAMETER | DESCRIPTION | | ------------ | ------------ | | **sent_from** | The full email address from which the target message was sent. | | **sent_to** | The full email address to which the target message was sent. | | **subject** | The subject line of the target email. | | **body** | Search for part of the message body. | | **match** | If set to `ALL` (default), then only results that match all specified criteria will be returned. If set to `ANY`, results that match any of the specified criteria will be returned. | ##### Options | PARAMETER | DESCRIPTION | | ------------ | ------------ | | **timeout** | If provided, determines how long to wait for a matching result (provided in milliseconds). | | **error_on_timeout** | When set to `False`, an error will not be thrown if timeout is reached (default: `True`). | | **received_after** | Allows you to customise how far back to look for messages. | | **page** | Used alongside `items_per_page` to paginate through results. This is zero-based, meaning `0` is the first page of results. | | **items_per_page** | A limit on the number of results to be returned. This can be set between 1 to 1000, with the default being 50. | ```python from mailosaur.models import SearchCriteria # ... criteria = SearchCriteria() criteria.sent_to = "someone@SERVER_ID.mailosaur.net" # Search for all messages sent to someone@SERVER_ID.mailosaur.net, # received in the last 2 hours. Limit results to the first 10 matches only. two_hours_ago=datetime.today() - timedelta(hours=2) result = mailosaur.messages.search('SERVER_ID', criteria, page=0, items_per_page=10, received_after=two_hours_ago) ``` #### messages.get_by_id(id) Retrieves the detail for a single email message. Must be used in conjunction with either [`list`](#messageslistserver-options) or [`search`](#messagessearchserver-criteria-options) in order to get the unique identifier for the required message. **We always recommend using the** [`get`](#messagesgetserver-criteria-options) **method instead**. ```python result = mailosaur.messages.list("SERVER_ID") message_id = result.items[0].id message = mailosaur.messages.get_by_id(message_id) print('Subject: ' + message.subject) ``` #### messages.delete(id) Permanently deletes a message. Also deletes any attachments related to the message. This operation cannot be undone. ```python mailosaur.messages.delete(message_id) ``` #### messages.delete_all(server) Permanently deletes all messages held in the specified inbox. Also deletes any attachments related to each message. This operation cannot be undone. ```python mailosaur.messages.delete_all("SERVER_ID") ``` #### messages.create(server, options) Creates a new message that can be sent to a verified email address. This is useful in scenarios where you want an email to trigger a workflow in your product. ```python from mailosaur.models import MessageCreateOptions # ... options = MessageCreateOptions() options.to = "verified-address@example.com" options.send = True options.subject = "Request" options.text = "Please can you give us a call back?" mailosaur.messages.create("SERVER_ID", options) ``` ##### Options - **to** The email address to which the email will be sent. Must be a verified email address. - **send** If true, email will be sent upon creation. - **subject** The email subject line. - **text** The plain text body of the email. - **html** The HTML body of the email. #### messages.forward(messageId, options) Forwards the specified email to a verified email address. ```python from mailosaur.models import MessageForwardOptions # ... options = MessageForwardOptions() options.to = "verified-address@example.com" options.text = "FYI" mailosaur.messages.forward("MESSAGE_ID", options) ``` ##### Options - **to** The email address to which the email will be sent. Must be a verified email address. - **text** Any additional plain text content to forward the email with. - **html** Any additional HTML content to forward the email with. #### messages.reply(messageId, options) Sends a reply to the specified email. This is useful for when simulating a user replying to one of your emails. ```python from mailosaur.models import MessageReplyOptions # ... options = MessageReplyOptions() options.text = "FYI" mailosaur.messages.reply("MESSAGE_ID", options) ``` ##### Options - **text** Any additional plain text content to include in the reply. - **html** Any additional HTML content to include in the reply. ### Servers Inboxes capture emails and SMS messages, group your tests and settings, and manage access for your team. #### servers.list() Returns a list of your inboxes. Inboxes are returned sorted in alphabetical order. ```python result = mailosaur.servers.list() print('You have an inbox called: ' + result.items[0]["name"]) ``` #### servers.create(server) Creates a new inbox. Only the `name` property is required to create a new inbox via the API. ```python from mailosaur.models import ServerCreateOptions # ... options = ServerCreateOptions("My email tests") mailosaur.servers.create(options) ``` #### servers.get(id) Retrieves the detail for a single inbox. Simply supply the unique identifier for the required inbox. ```python server = mailosaur.servers.get("SERVER_ID") ``` #### servers.get_password(id) Retrieves the password, for use with SMTP and POP3, for a single inbox. Simply supply the unique identifier for the required inbox. ```python password = mailosaur.servers.get_password("SERVER_ID") ``` #### servers.update(id, server) Updates a single inbox. ```python retrieved_server = mailosaur.servers.get("SERVER_ID") retrieved_server.name = "Updated inbox name" mailosaur.servers.update(retrieved_server.id, retrieved_server) ``` #### servers.delete(id) Permanently deletes an inbox. Also deletes all messages and associated attachments within the inbox. This operation cannot be undone. ```python mailosaur.servers.delete("SERVER_ID") ``` #### servers.generate_email_address(id) Utility method to help you generate a random email address for a given inbox. ```python email_address = mailosaur.servers.generate_email_address("SERVER_ID") print(email_address) # "bgwqj@SERVER_ID.mailosaur.net" ``` To learn about inbox IDs, and what to replace `SERVER_ID` with, see [sending email to Mailosaur](/docs/email-testing/sending-to-mailosaur). ### Files #### files.get_email(message_id) Downloads an EML file representing the specified email. Simply supply the unique identifier for the required email. #### files.get_attachment(attachment_id) Downloads a single attachment. Simply supply the unique identifier for the required attachment. ### Analysis #### analysis.spam(message_id) Perform spam testing on the specified email. ### Usage #### usage.limits() Retrieve account usage limits. Details the current limits and usage for your account. This endpoint requires authentication with an account-level API key. #### usage.transactions() Retrieves the last 31 days of transactional usage. This endpoint requires authentication with an account-level API key.