Add mailboxes in bulk
Connect one or multiple mailboxes to your account by providing SMTP/IMAP credentials along with optional sending configurations. This endpoint enables you to set up the connection but you can also specify additional settings, including daily sending limits, tracking domains or footers.
You can use this endpoint to connect Gmail and Outlook mailboxes in bulk as well, provided you are using dedicated app passwords instead of regular credentials.
Request
Endpoint
POST https://api.woodpecker.co/rest/v2/mailboxes/manual_connection/bulk
Headers
x-api-key: {YOUR_API_KEY}
Content-type: application/json
For details on how to authenticate your requests, please see the authentication guide.
Body
The request body contains a mailboxes
array where each object represents a mailbox with its SMTP/IMAP connection credentials and optional settings (like sending limits, tracking domains, and notification preferences). You can provide one or multiple mailbox configurations in a single request.
You can connect up to 200 mailboxes in a single request.
- All available fields
- Only required fields
{
"mailboxes": [
{
"smtp_email": "smtp@mail.com",
"smtp_login": "smtp-username",
"smtp_password": "secret-smtp-password",
"smtp_server": "smtp.server.io",
"smtp_port": 465,
"smtp_from_name": "smtp-from-name",
"imap_email": "imap@mail.com",
"imap_password": "secret-imap-password",
"imap_server": "imap.server.io",
"imap_port": 993,
"footer": "<div>Best regards,</div><div>John</div>",
"bcc": "email-to@bcc.com",
"open_tracking_domain": "open-domain.com",
"click_tracking_domain": "click-domain.com",
"unsubscribe_tracking_domain": "unsubscribe-domain.com",
"sending_wait_time_from": 10,
"sending_wait_time_to": 20,
"daily_sending_limit": 100
}
],
"completion_notification_types": ["MAIL", "IN_APP"]
}
{
"mailboxes": [
{
"smtp_email": "jared@getpiedpiper.com",
"smtp_password": "secret-smtp-password",
"smtp_server": "smtp.server.io",
"smtp_port": 465,
"imap_email": "jared@getpiedpiper.com",
"imap_password": "secret-imap-password",
"imap_server": "imap.server.io",
"imap_port": 993
}
]
}
Body schema
Field | Type | Required | Description |
---|---|---|---|
mailboxes | array | Yes | Array of mailbox configurations |
└─smtp_email | string | Yes | Email address of the sending mail |
└─smtp_login | string | No | Username for SMTP authentication. Use if it's different than the email |
└─smtp_password | string | Yes | Password for SMTP authentication |
└─smtp_server | string | Yes | SMTP server hostname |
└─smtp_port | integer | Yes | SMTP server port number |
└─smtp_from_name | string | No | Sender's display name shown to recipients |
└─imap_email | string | Yes | Email address of the receiving mail |
└─imap_password | string | Yes | Password for IMAP authentication |
└─imap_server | string | Yes | IMAP server hostname |
└─imap_port | integer | Yes | IMAP server port number |
└─footer | string | No | Signature added to sent emails, in HTML format |
└─bcc | string | No | Email address to be added as BCC in all outgoing emails. Useful with CRMs |
└─open_tracking_domain | string | No | Custom domain used to track email opens |
└─click_tracking_domain | string | No | Custom domain used to track link clicks |
└─unsubscribe_tracking_domain | string | No | Custom domain handling unsubscribe requests |
└─sending_wait_time_from | integer | No* | Minimum pause between emails in seconds (range: 10-9999) |
└─sending_wait_time_to | integer | No* | Maximum pause between emails in seconds (range: 20-9999) |
└─daily_sending_limit | integer | No | Maximum number of sent emails allowed per day (range: 1-5500) |
completion_notification_types | string[] | No | How to notify you when batch processing completes: via email MAIL and/or in-app notification IN_APP |
*Note: If either sending_wait_time_from
or sending_wait_time_to
is provided, both become required and from
must be less than to
.
Request sample
Connect a mailbox
- cURL
- Java
- Node.js
curl --request POST \
--url "https://api.woodpecker.co/rest/v2/mailboxes/manual_connection/bulk" \
--header "x-api-key: {YOUR_API_KEY}" \
--header "Content-Type: application/json" \
--data '{
"mailboxes": [
{
"smtp_email": "jared@getpiedpiper.com",
"smtp_password": "secret-smtp-password",
"smtp_server": "smtp.server.io",
"smtp_port": 465,
"imap_email": "jared@getpiedpiper.com",
"imap_password": "secret-imap-password",
"imap_server": "imap.server.io",
"imap_port": 993
}
]
}'
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
public class WoodpeckerApiClient {
public static void main(String[] args) {
String apiKey = "YOUR_API_KEY";
String endpoint = "https://api.woodpecker.co/rest/v2/mailboxes/manual_connection/bulk";
String jsonInputString = "{"
+ "\"mailboxes\": ["
+ "{"
+ "\"smtp_email\": \"jared@getpiedpiper.com\","
+ "\"smtp_password\": \"secret-smtp-password\","
+ "\"smtp_server\": \"smtp.server.io\","
+ "\"smtp_port\": 465,"
+ "\"imap_email\": \"jared@getpiedpiper.com\","
+ "\"imap_password\": \"secret-imap-password\","
+ "\"imap_server\": \"imap.server.io\","
+ "\"imap_port\": 993"
+ "}"
+ "]"
+ "}";
try {
URL url = new URL(endpoint);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("x-api-key", apiKey);
connection.setRequestProperty("Content-Type", "application/json");
connection.setDoOutput(true);
try (OutputStream os = connection.getOutputStream()) {
byte[] input = jsonInputString.getBytes(StandardCharsets.UTF_8);
os.write(input, 0, input.length);
}
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_CREATED) {
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String inputLine;
StringBuilder response = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
System.out.println("Response: " + response.toString());
} else {
System.out.println("POST request failed with response code: " + responseCode);
}
connection.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
}
const axios = require("axios");
const apiKey = "YOUR_API_KEY";
const url = "https://api.woodpecker.co/rest/v2/mailboxes/manual_connection/bulk";
const data = {
mailboxes: [
{
smtp_email: "jared@getpiedpiper.com",
smtp_password: "secret-smtp-password",
smtp_server: "smtp.server.io",
smtp_port: 465,
imap_email: "jared@getpiedpiper.com",
imap_password: "secret-imap-password",
imap_server: "imap.server.io",
imap_port: 993,
},
],
};
axios
.post(url, data, {
headers: {
"x-api-key": apiKey,
"Content-Type": "application/json",
},
})
.then((response) => {
console.log("Response:", response.data);
})
.catch((error) => {
console.error("Error:", error.response ? error.response.data : error.message);
});
Response
Response examples
- 202
- 400
- 401
- 404
- 409
- 500
The response includes a batch_id
that allows you to monitor the progress and results of the submitted mailbox connections using rest/v2/mailboxes/manual_connection/bulk/{batch_id}/summary endpoint.
{
"batch_id": 123456
}
Body schema
Field | Type | Description |
---|---|---|
batch_id | string | ID of the submitted email batch. Use it to review the connection status. |
Invalid request or malformed request syntax. Please review the request body and field requirements.
Each validation error will be included in the details
array. For example, mailbox[3].daily_sending_limit
indicates the issue encountered while validating the daily_sending_limit
for the fourth mailbox in your request. Below are a few additional examples.
{
"code": "VALIDATION_FAILURE",
"details": [
"mailbox[0].smtp_password must not be blank",
"mailbox[0].imap_port must be provided and in range <1,65535>",
"mailbox[0].sending_wait_time_from if provided must be present along with and lower than sending_wait_time_to and be in range <10,9999>",
"mailbox[0].sending_wait_time_to if provided must be present along with and higher than sending_wait_time_from and be in range <20,9999>",
"mailbox[0].open_tracking_domain if provided must be a valid domain"
]
}
Body schema
Field | Type | Description |
---|---|---|
code | string | Code that outlines the request issue. VALIDATION_FAILURE or UNKNOWN |
details[] | array | Array of specific error messages. If the code is VALIDATION_FAILURE , every field with an issue will be returned as mailbox[index].filed message |
An issue with authorization. Please review the authorization guide
{
"title": "Unauthorized",
"status": 401,
"detail": "Invalid api key",
"timestamp": "2025-03-05 17:57:00"
}
Body schema
Field | Type | Description |
---|---|---|
title | string | A short title describing the error |
status | integer | The HTTP status code |
detail | string | A detailed message explaining the error |
timestamp | string | The timestamp when the error occurred, YYYY-MM-DD HH:MM:SS UTC |
Please review the request URL
{
"title": "Not Found",
"status": 404,
"detail": "Requested resource does not exist",
"timestamp": "2025-03-05 17:57:00"
}
Body schema
Field | Type | Description |
---|---|---|
title | string | A short title describing the error |
status | integer | The HTTP status code |
detail | string | A detailed message explaining the error |
timestamp | string | The timestamp when the error occurred, YYYY-MM-DD HH:MM:SS UTC |
Conflict
{
"code": "Conflict",
"details": [
"string"
]
}
Unknown error, please try again later
{
"title": "Internal server error",
"status": 500,
"detail": "An unexpected error has occurred. Please try again later.",
"timestamp": "2025-03-05 17:57:00"
}
Body schema
Field | Type | Description |
---|---|---|
title | string | A short title describing the error |
status | integer | The HTTP status code |
detail | string | A detailed message explaining the error |
timestamp | string | The timestamp when the error occurred, YYYY-MM-DD HH:MM:SS UTC |