Move & Read emails

Learn how to move and read emails using Unipile API.

Change read status

To mark an email as read, use Read an Email and provide the Email ID.

await emailsApi.readEmail({
  path: {
    account_id: "acc_123456789",
    email_id: "email_id",
  },
});
emails_api.read_email("acc_123456789", "email_id")
curl --request POST \
     --url https://api.unipile.com/v2/account_id/emails/email_id/read \
     --header 'accept: application/json'
📘

Note on tracking pixels

Marking an email as read only affects the account owner, not the sender. If the email uses a tracking mechanism (such as a tracking pixel) to detect opens, it will not be triggered, as this requires loading external URLs.


To mark an email as unread, use Unread an Email and provide the Email ID.

await emailsApi.unreadEmail({
  path: {
    account_id: "acc_123456789",
    email_id: "email_id",
  },
});
emails_api.unread_email("acc_123456789", "email_id")
curl --request POST \
     --url https://api.unipile.com/v2/account_id/emails/email_id/unread \
     --header 'accept: application/json'

Move an email

To move an email from one folder to another, use Modify an Email and provide the email ID along with the destination folder ID.

📘

The folders_ids field is required for IMAP. If omitted, the email is not moved — useful when only updating provider-specific properties (e.g. categories).

❗️

Gmail specificity

In Gmail’s apps, the "Move to..." action works by removing the current label that acts as a folder (e.g., Inbox, Categories, or custom labels) and replacing it with a new one, while keeping other labels such as Important, Starred, or additional custom labels.

When using Modify an Email in Unipile, all labels are removed before applying the new one.

To replicate Gmail’s native behavior, include the IDs of any labels you want to keep in your request.

const { data } = await emailsApi.modifyEmail({
  path: {
    account_id: "acc_123456789",
    email_id: "email_id",
  },
  body: {
    folders_ids: ["folder_id"],
  },
});
emails_api.modify_email(
    "acc_123456789",
    "email_id",
    {"folders_ids": ["folder_id"]},
)
curl --request POST \
     --url https://api.unipile.com/v2/account_id/emails/email_id/modify \
     --header 'accept: application/json' \
     --header 'content-type: application/json'

Label an email

On Gmail only, to label an email, use Modify an Email and provide the email ID along with the list of current folder (label) IDs, plus the ID of the new folder (label).

const emailId = "email_id";

const { data: email } = await emailsApi.getEmail({
  path: {
    account_id: "acc_123456789",
    email_id: emailId,
  },
});

await emailsApi.modifyEmail({
  path: {
    account_id: "acc_123456789",
    email_id: emailId,
  },
  body: {
    folders_ids: [
      ...(email.folders ?? []).map((folder) => folder.id),
      "folder_id",
    ],
  },
});
email_id = "email_id"
email = emails_api.get_email("acc_123456789", email_id)

folder_ids = [folder.id for folder in (email.folders or []) if folder.id]
folder_ids.append("folder_id")

emails_api.modify_email(
    "acc_123456789",
    email_id,
    {"folders_ids": folder_ids},
)

Categorize an email (Outlook)

On Outlook only, you can assign categories to an email using Modify an Email and the specifics.outlook.categories field.

The specifics.{provider} pattern is the same as on routes like CreatePost and UpdateUserProfile.

📘

Notes

  • Categories that don't exist yet in the account's master categories are automatically created with the default color "None".
  • The categories field in the Email response is always an empty array [] for providers other than Outlook.

Assign categories only (no folder move)

await emailsApi.modifyEmail({
  path: {
    account_id: "acc_123456789",
    email_id: "email_id",
  },
  body: {
    specifics: {
      outlook: {
        categories: ["Project X", "Urgent"],
      },
    },
  },
});
emails_api.modify_email(
    "acc_123456789",
    "email_id",
    {
        "specifics": {
            "outlook": {
                "categories": ["Project X", "Urgent"],
            },
        },
    },
)
curl --request POST \
     --url https://api.unipile.com/v2/account_id/emails/email_id/modify \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --data '{"specifics":{"outlook":{"categories":["Project X","Urgent"]}}}'

Move to folder + assign categories

await emailsApi.modifyEmail({
  path: {
    account_id: "acc_123456789",
    email_id: "email_id",
  },
  body: {
    folders_ids: ["folder_id"],
    specifics: {
      outlook: {
        categories: ["Project X", "Urgent"],
      },
    },
  },
});
emails_api.modify_email(
    "acc_123456789",
    "email_id",
    {
        "folders_ids": ["folder_id"],
        "specifics": {
            "outlook": {
                "categories": ["Project X", "Urgent"],
            },
        },
    },
)
curl --request POST \
     --url https://api.unipile.com/v2/account_id/emails/email_id/modify \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --data '{"folders_ids":["folder_id"],"specifics":{"outlook":{"categories":["Project X","Urgent"]}}}'

Trash an email

Most providers expose a special-use folder \Trash where messages are retained temporarily before permanent deletion.
You can move a message there with Modify an Email, but we recommend using Trash an Email. This endpoint ensures the message is routed to the provider’s correct trash location and respects provider-specific retention behavior.

await emailsApi.trashEmail({
  path: {
    account_id: "acc_123456789",
    email_id: "email_id",
  },
});
emails_api.trash_email("acc_123456789", "email_id")
curl --request DELETE \
     --url https://api.unipile.com/v2/account_id/emails/email_id \
     --header 'accept: application/json'

Archive, junk or flag an email

To archive, junk, or flag an Email, simply move it to the folder with the associated role :

  • Archive : ARCHIVE
  • Junk : JUNK
  • Flag : FLAGGED

From the list of folders, find the ID of the wanted folder then use Modify an Email and provide the ID to move with the destination folder ID.

const { data: folders } = await emailsApi.getFoldersList({
  path: {
    account_id: "acc_123456789",
  },
  query: {
    limit: 20,
  },
});

// Example to archive

const ARCHIVE_FOLDER_ID = folders.data?.find(
  (folder) => folder.role === "ARCHIVE",
)?.id;

// Make sure the special-use folder exists, some IMAP providers may not have it.
if (ARCHIVE_FOLDER_ID) {
  await emailsApi.modifyEmail({
    path: {
      account_id: "acc_123456789",
      email_id: "email_id",
    },
    body: {
      folders_ids: [ARCHIVE_FOLDER_ID],
    },
  });
}
folders = emails_api.get_folders_list("acc_123456789", limit=20)
archive_folder = next(
    (folder for folder in (folders.data or []) if folder.role == "ARCHIVE"),
    None,
)

if archive_folder:
    emails_api.modify_email(
        "acc_123456789",
        "email_id",
        {"folders_ids": [archive_folder.id]},
    )

What’s Next