Email Forwarding API
This is the documentation for our API endpoints at improvmx.com. This lets you list, create, edit and remove domains and email aliases that you can forward to programmatically.
Base URL
The base URL of ImprovMX’s API is: https://api.improvmx.com/v3
The v3
api was released on April 30th, 2020. We suggest you update as soon as possible.
The v2
api has been marked as deprecated and was removed on June 1st 2024.
Authentication
First, retrieve your API Key from the API page of the ImprovMX app dashboard.
Authentication is done via basic access authentication.
Pass the string api
as the username and your API key as the password, like in the following curl request:
export API_KEY={your_api_key}
curl https://api.improvmx.com/v3/domains \
-H "Authorization: Basic api:$API_KEY"
That’s it, now you’re ready to communicate with our API.
Error codes
Here are the main error codes you will encounter:
Code | Description |
---|---|
200 | Success The request was successful. |
400 | Bad Request You passed an incorrect or missing parameter. |
401 | Authentication required You tried to access an endpoint that requires authentication but you are not properly authenticated. |
403 | Forbidden You don’t have permissions to access or edit this endpoint, e.g. a premium account is required. |
500 | Server error We ran into a bug… Reach out to us and we’ll fix it 🙂 |
When an error occurs, you will always receive a JSON response in the body explaining the reason for the failure. This should help you understand and fix your subsequent requests.
For instance, here’s an example of a Bad Request
response returned by the server:
{
"errors": {
"email": [
"You cannot use your domain in your email."
]
},
"success": false
}
Account
GET /account
Get details about your ImprovMX account
curl -X GET https://api.improvmx.com/v3/account \
-H "Authorization: Basic api:$API_KEY"
Returns JSON like the following:
{
"account": {
"billing_email": null,
"cancels_on": null,
"card_brand": "Visa",
"company_details": "1 Decentralized Street\n92024-
2852 California",
"company_name": "PiedPiper Inc.",
"company_vat": null,
"country": "US",
"created": 1512139382000,
"email": "richard.hendricks@gmail.com",
"last4": "1234",
"limits": {
"aliases": 10000,
"daily_quota": 100000,
"daily_send": 200,
"domains": 10000,
"ratelimit": 10,
"redirections": 50,
"subdomains": 2,
"api": 3,
"credentials": 50,
"destinations": 5
},
"lock_reason": null,
"locked": null,
"password": true,
"plan": {
"aliases_limit": 10000,
"daily_quota": 100000,
"display": "Business - $249",
"domains_limit": 10000,
"kind": "enterprise",
"name": "enterprise249",
"price": 249,
"yearly": false
},
"premium": true,
"privacy_level": 1,
"renew_date": 15881622590000
},
"success": true
}
GET /account/whitelabels
Get whitelabeled domains
curl -X GET https://api.improvmx.com/v3/account/whitelabels \
-H "Authorization: Basic api:$API_KEY"
Returns JSON like the following:
{
"whitelabels": [
{
"name": "piedpiper.com"
}
],
"success": true
}
Domains
GET /domains
Retrieve a list of all your domains
curl -X GET https://api.improvmx.com/v3/domains \
-H "Authorization: Basic api:$API_KEY"
Parameter | Type | Required? | Description |
---|---|---|---|
q | String | False | Search the domains starting from this value. |
is_active | Boolean | False | Returns only active (1 ) or inactive (0 ) domains. |
limit | Integer | False | Number of domains returned. Defaults to 50. Allowed values between 5 and 100. |
page | Integer | False | Current page to load. 1-based (The first, default page is at page = 1). |
Note: We limit to 200 aliases returned in each domain in this endpoint. If your domain has more, we recommend using the list aliases endpoint!
Returns JSON like the following:
{
"domains": [
{
"active": true,
"domain": "google.com",
"display": "google.com",
"dkim_selector": "dkimprovmx",
"notification_email": null,
"webhook": null,
"whitelabel": null,
"added": 1559639697000,
"aliases": [
{
"created": 1702393755000,
"forward": "sergey@gmail.com",
"alias": "sergey",
"id": 1
},
{
"created": 1702393755000,
"forward": "larry@gmail.com",
"alias": "larry",
"id": 2
}
]
},
{
"active": false,
"domain": "piedpiper.com",
"display": "piedpiper.com",
"dkim_selector": "dkimprovmx",
"notification_email": null,
"whitelabel": null,
"added": 1559639733000,
"aliases": [
{
"created": 1702393755000,
"forward": "richard.hendricks@gmail.com",
"alias": "richard",
"id": 4
},
{
"created": 1702393755000,
"forward": "jared.dunn@gmail.com",
"alias": "jared",
"id": 5
}
]
}
],
"total": 3,
"limit": 50,
"page": 1,
"success": true
}
You can also use the q
parameter to search for domains that start with the given value.
curl -X GET https://api.improvmx.com/v3/domains?q=pied \
-H "Authorization: Basic api:$API_KEY"
Returns JSON like the following:
{
"domains": [
{
"active": true,
"domain": "piedpiper.com",
"display": "piedpiper.com",
"dkim_selector": "dkimprovmx",
"notification_email": null,
"webhook": null,
"whitelabel": null,
"added": 1559639727000,
"daily_quota": 500,
"aliases": [
{
"created": 1702393755000,
"forward": "richard@piedpiper.com",
"alias": "*",
"id": 3
}
]
}
],
"total": 1,
"limit": 50,
"page": 1,
"success": true
}
POST /domains
Add a new domain
curl -X POST https://api.improvmx.com/v3/domains \
-H "Authorization: Basic api:$API_KEY" \
-H 'Content-Type: application/json' \
-d '{"domain": "piedpiper.com"}'
Parameter | Type | Required? | Description |
---|---|---|---|
domain | String | True | Name of the domain |
notification_email | String | False | Email to send notifications to |
whitelabel | String | False | Parent’s domain that will be displayed for the DNS settings. |
Returns JSON like the following:
{
"domain": {
"active": false,
"domain": "piedpiper.com",
"display": "piedpiper.com",
"dkim_selector": "dkimprovmx",
"notification_email": null,
"whitelabel": null,
"added": 1559652806000,
"aliases": [
{
"forward": "contact@piedpiper.com",
"alias": "*",
"id": 12
}
]
},
"success": true
}
GET /domains/:domain
Get domain details
curl -X GET https://api.improvmx.com/v3/domains/piedpiper.com \
-H "Authorization: Basic api:$API_KEY"
Note: We limit this endpoint to 200 aliases per domain. If your domain has more aliases, we recommend the list aliases endpoint.
Returns JSON like the following:
{
"domain": {
"active": false,
"domain": "piedpiper.com",
"added": 1559639733000,
"display": "piedpiper.com",
"dkim_selector": "dkimprovmx",
"notification_email": null,
"webhook": null,
"whitelabel": null,
"aliases": [
{
"created": 1702393755000,
"forward": "richard.hendricks@gmail.com",
"alias": "richard",
"id": 4
},
{
"created": 1702393755000,
"forward": "jared.dunn@gmail.com",
"alias": "jared",
"id": 5
}
]
},
"success": True
}
PUT /domains/:domain
Edit a domain.
NOTE: It’s not possible to change the domain name.
curl -X PUT https://api.improvmx.com/v3/domains/piedpiper.com \
-H "Authorization: Basic api:$API_KEY" \
-H 'Content-Type: application/json' \
-d '{"notification_email": "email@example.com",
"webhook": "https://requestbin.com/r/abc123",
"whitelabel": "hooli.com"}'
Parameter | Type | Required? | Description |
---|---|---|---|
notification_email | String (email) | False | Email where notifications related to the domain will be sent |
webhook | String (URL) | False | URL where email events related to this domain will be sent |
whitelabel | String | False | The parent’s domain owner |
Returns JSON like the following:
{
"domain": {
"active": false,
"domain": "piedpiper.com",
"added": 1559639733000,
"display": "piedpiper.com",
"dkim_selector": "dkimprovmx",
"notification_email": "email@example.com",
"webhook": "https://requestbin.com/r/enbwnegkb25v",
"whitelabel": "hooli.com",
"aliases": [
{
"forward": "richard.hendricks@gmail.com",
"alias": "richard",
"id": 4
},
{
"forward": "jared.dunn@gmail.com",
"alias": "jared",
"id": 5
}
]
},
"success": True
}
DELETE /domains/:domain
Delete a domain
curl -X DELETE https://api.improvmx.com/v3/domains/piedpiper.com \
-H "Authorization: Basic api:$API_KEY"
Returns JSON like the following:
{
"success": true
}
GET /domains/:domain/check
Check if MX entries are valid for a domain
curl -X GET https://api.improvmx.com/v3/domains/piedpiper.com/check \
-H "Authorization: Basic api:$API_KEY"
Returns JSON like the following:
{
"records": {
"provider": "cloudflare",
"advanced": true,
"dkim1": {
"expected": "dkimprovmx1.improvmx.com.",
"valid": true,
"values": "dkimprovmx1.improvmx.com."
},
"dkim2": {
"expected": "dkimprovmx2.improvmx.com.",
"valid": true,
"values": "dkimprovmx2.improvmx.com."
},
"dmarc": {
"expected": "v=DMARC1; p=none;",
"valid": false,
"values": null
},
"error": null,
"mx": {
"expected": [
"mx1.improvmx.com",
"mx2.improvmx.com"
],
"valid": true,
"values": [
"mx2.improvmx.com",
"mx1.improvmx.com"
]
},
"spf": {
"expected": "v=spf1 include:someservice.org include:spf.improvmx.com ~all",
"valid": false,
"values": "v=spf1 include:someservice.org ~all"
},
"valid": false
},
"success": true
}
The endpoint will return success: true
when MX entries are well configured, success: false
otherwise.
error
may contain a reason why the entries are not valid.
Aliases
GET /domains/:domain/aliases
List a domain’s aliases
curl -X GET https://api.improvmx.com/v3/domains/piedpiper.com/aliases \
-H "Authorization: Basic api:$API_KEY"
Parameter | Type | Required? | Description |
---|---|---|---|
q | String | False | Search (both alias and destination) starting by this value. |
alias | String | False | Search only the alias value that starts with the given value. |
is_active | Boolean | False | Returns only active (1 ) or inactive (0 ) domains. |
page | Integer | False | Current page to load. 1-based (The first, default page is at page = 1). |
Returns JSON like the following:
{
"aliases": [
{
"created": 1702982672000,
"forward": "richard.hendricks@gmail.com",
"alias": "richard",
"id": 4
},
{
"created": 1702982672000,
"forward": "jared.dunn@gmail.com",
"alias": "jared",
"id": 5
}
],
"limit": 5,
"page": 1,
"total": 2,
"success": true
}
POST /domains/:domain/aliases
Add new domain alias
curl -X POST https://api.improvmx.com/v3/domains/piedpiper.com/aliases \
-H "Authorization: Basic api:$API_KEY" \
-H 'Content-Type: application/json' \
-d '{"alias": "richard",
"forward": "richard.hendricks@gmail.com"}'
Parameter | Type | Required? | Description |
---|---|---|---|
alias | String | True | Alias to be used in front of your domain, like “contact”, “info”, etc. |
forward | String (email) | True | Destination email to forward emails to |
{
"alias": {
"forward": "richard.hendricks@gmail.com",
"alias": "richard",
"id": 11
},
"success": true
}
GET /domains/:domain/aliases/:alias
Get alias details
curl -X GET https://api.improvmx.com/v3/domains/piedpiper.com/aliases/richard \
-H "Authorization: Basic api:$API_KEY"
Returns JSON like the following:
{
"alias": {
"created": 1702982672000,
"forward": "richard.hendricks@protonmail.com",
"alias": "richard",
"id": 11
},
"success": true
}
PUT /domains/:domain/aliases/:alias
Update an alias
curl -X PUT https://api.improvmx.com/v3/domains/piedpiper.com/aliases/richard \
-H "Authorization: Basic api:$API_KEY" \
-H 'Content-Type: application/json' \
-d '{"forward": "richard.hendricks@protonmail.com"}'
Parameter | Type | Required? | Description |
---|---|---|---|
forward | String (email) | True | Destination email to forward emails to |
Returns JSON like the following:
{
"alias": {
"forward": "richard.hendricks@protonmail.com",
"alias": "richard",
"id": 11
},
"success": true
}
You can also update an alias based on the “id” which is generated by our system when an alias is created
curl -X PUT https://api.improvmx.com/v3/domains/piedpiper.com/aliases/7 \
-H "Authorization: Basic api:$API_KEY" \
-H 'Content-Type: application/json' \
-d '{"alias": "richard2",
"forward": "richard.hendricks@protonmail.com"}'
Parameter | Type | Required? | Description |
---|---|---|---|
alias | String | False | Alias to be used in front of your domain, like “contact”, “info”, etc. |
forward | String (email) | False | Destination email to forward emails to |
Returns JSON like the following:
{
"alias": {
"forward": "richardhendricks@gmail.com",
"alias": "richardhendricks",
"id": 11
},
"success": true
}
DELETE /domains/:domain/aliases/:alias
Delete an alias
curl -X DELETE https://api.improvmx.com/v3/domains/piedpiper.com/aliases/nelson \
-H "Authorization: Basic api:$API_KEY"
Returns JSON like the following:
{
"success": true
}
POST /domains/:domain/aliases/bulk
Add aliases in bulk
curl -X POST https://api.improvmx.com/v3/domains/piedpiper.com/aliases/bulk \
-H "Authorization: Basic api:$API_KEY" \
-H 'Content-Type: application/json' \
-d '{"aliases":[
{"alias":"richard","forward":"richard.hendricks@gmail.com"},
{"alias":"jared", "forward":"jared.dunn@gmail.com"}]
"behavior": "update"}'
Parameter | Type | Required? | Description |
---|---|---|---|
aliases | Array | True | An array containing a list of up to 500 objects with “alias” (your alias) and “forward” (the destination email) |
behavior | String | False | Setting it to “add” (default) will cause the request to fail if the alias already exists. Setting it to “update” will update an existing alias. |
Returns JSON like the following:
{
"added": [
{
"alias": "richard",
"forward": "richard.hendricks@gmail.com",
"id": 12345
},
{
"alias": "jared",
"forward": "jared.dunn@gmail.com",
"id": 12346
}
],
"failed": [
{
"alias": "monica",
"forward": "monica.hall@gmail.com",
"id": 12347
}
],
"success": true,
"updated": [
{
"alias": "dinesh",
"forward": "dinesh.chugtai@gmail.com",
"id": 12348
},
{
"alias": "bertram",
"forward": "bertram.gilfoyle@gmail.com",
"id": 12349
}
]
}
Logs
GET /domains/:domain/logs
Get domain logs
curl -X GET https://api.improvmx.com/v3/domains/piedpiper.com/logs \
-H "Authorization: Basic api:$API_KEY"
Parameter | Type | Required? | Description |
---|---|---|---|
next_cursor | String | False | Loads the logs after the given log.id. (Like 20201002014128.7ea8ee59fa894aa7a91415a6659c5b46 ) |
Returns JSON like the following:
{
"logs": [
{
"created": "2020-01-25 12:19:09+0000",
"created_raw": "Sat, 25 Jan 2020 12:19:09 GMT",
"events": [
{
"code": 250,
"created": "2020-01-25 12:19:11+0000",
"id": "some_random_id",
"local": "mxb.infra.improvmx.com",
"message": "Queued",
"server": "mail-io1-f54.google.com",
"status": "QUEUED"
},
{
"code": 250,
"created": "2020-01-25 12:19:12+0000",
"id": "some_random_id",
"local": "gmail-smtp-in.l.google.com",
"message": "Sent.",
"server": "mail16.mxc.infra.improvmx.com",
"status": "DELIVERED"
}
],
"forward": {
"email": "richard.hendricks@gmail.com",
"name": "Richard Hendricks"
},
"hostname": "mail-io1-f54.google.com",
"id": "20201002014128.5ea8ee59fa894aa7a9141e9665985b46",
"messageId": "some_random_id",
"recipient": {
"email": "richard@piedpiper.com",
"name": "Richard Hendricks"
},
"sender": {
"email": "gavin@hooli.com",
"name": "Gavin Belsonx"
},
"subject": "You are screwed, Piedpiper team!",
"transport": "smtp"
},
{
"created": "2020-01-25 12:18:46+0000",
"created_raw": "Sat, 25 Jan 2020 12:18:46 GMT",
"events": [
{
"code": 250,
"created": "2020-01-25 12:18:47+0000",
"id": "another_random_id",
"local": "mxb.infra.improvmx.com",
"message": "Queued",
"server": "mail-pj1-f54.google.com",
"status": "QUEUED"
},
{
"code": 250,
"created": "2020-01-25 12:18:47+0000",
"id": "another_random_id",
"local": "gmail-smtp-in.l.google.com",
"message": "Sent.",
"server": "mail15.mxb.infra.improvmx.com",
"status": "DELIVERED"
}
],
"forward": {
"email": "monica.hall@gmail.com",
"name": "Monica Hall"
},
"hostname": "mail-pj1-f54.google.com",
"messageId": "another_random_id",
"recipient": {
"email": "monica@piedpiper.com",
"name": "Monica Hall"
},
"sender": {
"email": "russ@threecommas.com",
"name": "Russ Hanneman"
},
"subject": "Series A, bitches!",
"transport": "smtp"
},
{
"created": "2020-01-25 11:30:41+0000",
"created_raw": "Sat, 25 Jan 2020 11:30:41 GMT",
"events": [
{
"code": 550,
"created": "2020-01-25 11:30:42+0000",
"id": "yet_another_random_id",
"local": "mxa.infra.improvmx.com",
"message": "5.7.1 Message considered as SPAM (Score of 5.8/5.0 with BAYES_20, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, HTML_MESSAGE, HTML_TAG_BALANCE_BODY, MIME_HEADER_CTYPE_ONLY, NO_RELAYS, URIBL_ABUSE_SURBL, URIBL_DBL_ABUSE_SPAM, URIBL_DBL_SPAM)",
"server": "mail-wm1-f67.google.com",
"status": "REFUSED"
}
],
"forward": null,
"hostname": "mail-wm1-f67.google.com",
"id": "20201002014128.7ea8ee59fa894aa7a91415a6659c5b46",
"messageId": "yet_another_random_id",
"recipient": {
"email": "richard@piedpiper.com",
"name": null
},
"sender": {
"email": "spam@hooli.com",
"name": "ThinkTeam"
},
"subject": "Enlarge your (pied)piper!",
"transport": "smtp"
}
],
"success": true
}
The logs array will contain all the processed emails. Each entry in the array will contain a list of events, related to all the actions taken by ImprovMX servers, which are:
QUEUED | The email was accepted to be processed |
REFUSED | The email was refused at the SMTP connection |
DELIVERED | The email was successfully delivered to the end destination |
SOFT-BOUNCE | The end destination temporarily refused the email. We will retry multiple times with increasing delay. |
HARD-BOUNCE | The end destination rejected the email. |
GET /domains/:domain/logs/:alias
Get logs for a domain’s alias.
This behaves similarly to the general logs endpoint, but only returns results for the requested alias.
curl -X GET https://api.improvmx.com/v3/domains/piedpiper.com/logs/richard \
-H "Authorization: Basic api:$API_KEY"
Parameter | Type | Required? | Description |
---|---|---|---|
next_cursor | String | False | Loads the logs after the given log.id. (Like 20201002014128.7ea8ee59fa894aa7a91415a6659c5b46 ) |
NOTE: If you are requesting logs for a regex, you’ll need to URL-encode the characters, i.e. for (contact|support)
, you would make a request like domains/piedpiper.com/logs/%28contact%7Csupport%29
.
Returns JSON like the following:
{
"logs": [
{
"created": "2020-01-25 12:19:09+0000",
"created_raw": "Sat, 25 Jan 2020 12:19:09 GMT",
"events": [
{
"code": 250,
"created": "2020-01-25 12:19:11+0000",
"id": "some_random_id",
"local": "mxb.infra.improvmx.com",
"message": "Queued",
"server": "mail-io1-f54.google.com",
"status": "QUEUED"
},
{
"code": 250,
"created": "2020-01-25 12:19:12+0000",
"id": "some_random_id",
"local": "gmail-smtp-in.l.google.com",
"message": "Sent.",
"server": "mail16.mxc.infra.improvmx.com",
"status": "DELIVERED"
}
],
"forward": {
"email": "richard.hendricks@gmail.com",
"name": "Richard Hendricks"
},
"hostname": "mail-io1-f54.google.com",
"id": "20201002014128.5ea8ee59fa894aa7a9141e9665985b46",
"messageId": "some_random_id",
"recipient": {
"email": "richard@piedpiper.com",
"name": "Richard Hendricks"
},
"sender": {
"email": "gavin@hooli.com",
"name": "Gavin Belsonx"
},
"subject": "You are screwed, Piedpiper team!",
"transport": "smtp"
},
{
"created": "2020-01-25 11:30:41+0000",
"created_raw": "Sat, 25 Jan 2020 11:30:41 GMT",
"events": [
{
"code": 550,
"created": "2020-01-25 11:30:42+0000",
"id": "yet_another_random_id",
"local": "mxa.infra.improvmx.com",
"message": "5.7.1 Message considered as SPAM (Score of 5.8/5.0 with BAYES_20, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, HTML_MESSAGE, HTML_TAG_BALANCE_BODY, MIME_HEADER_CTYPE_ONLY, NO_RELAYS, URIBL_ABUSE_SURBL, URIBL_DBL_ABUSE_SPAM, URIBL_DBL_SPAM)",
"server": "mail-wm1-f67.google.com",
"status": "REFUSED"
}
],
"forward": null,
"id": "20201002014128.7ea8ee59fa894aa7a91415a6659c5b46",
"hostname": "mail-wm1-f67.google.com",
"messageId": "yet_another_random_id",
"recipient": {
"email": "richard@piedpiper.com",
"name": null
},
"sender": {
"email": "spam@hooli.com",
"name": "ThinkTeam"
},
"subject": "Enlarge your (pied)piper!",
"transport": "smtp"
}
],
"success": true
}
SMTP Credentials
NOTE: SMTP is a premium feature.
GET /domains/:domain/credentials
Get domain’s SMTP credentials
curl -X GET https://api.improvmx.com/v3/domains/piedpiper.com/credentials \
-H "Authorization: Basic api:$API_KEY"
Returns JSON like the following:
{
"credentials": [
{
"created": 1581604970000,
"usage": 0,
"username": "richard"
},
{
"created": 1581607028000,
"usage": 0,
"username": "monica"
}
],
"success": true
}
POST /domains/:domain/credentials
Add new SMTP credential
curl -X POST https://api.improvmx.com/v3/domains/piedpiper.com/credentials \
-H "Authorization: Basic api:$API_KEY" \
-H 'Content-Type: application/json' \
-d '{"username": "bighead", "password": "abc123"}'
Parameter | Type | Required? | Description |
---|---|---|---|
username | True | String | Left part of the mailbox, like bighead for the email bighead@piedpiper.com |
password | True | String | The password for this account. |
Returns JSON like the following:
{
"credential": {
"created": 1588236952000,
"usage": 0,
"username": "bighead"
},
"requires_new_mx_check": false,
"success": true
}
The response field requires_new_mx_check
will be True
when creating your first SMTP credential.
NOTE: When setting up SMTP for the first time, we require two new DKIM CNAME
entries and a new DMARC TXT entry in your DNS settings. Your domain will be unable to send SMTP until these are added.
PUT /domains/:domain/credentials/:username
Update SMTP credential
curl -X PUT https://api.improvmx.com/v3/domains/piedpiper.com/credentials/bighead \
-H "Authorization: Basic api:$API_KEY" \
-H 'Content-Type: application/json' \
-d '{"password": "abcd1234"}'
Returns JSON like the following:
{
"credential": {
"created": 1588236952000,
"usage": 0,
"username": "bighead"
},
"success": true
}
DELETE /domains/:domain/credentials/:username
Delete SMTP credential
curl -X DELETE https://api.improvmx.com/v3/domains/piedpiper.com/credentials/russ \
-H "Authorization: Basic api:$API_KEY"
Returns JSON like the following:
{
"success": true
}