Version:
Only show these results:

Send email messages

Nylas offers multiple ways to send email messages. This page describes how to choose the best method for your Nylas application, how to create and send a draft, and how to send an email message without creating a draft.

Choose how to send email messages

Nylas offers two different ways to send email messages:

  • Create and send a draft: This method is ideal for preparing email messages that don't need to be sent immediately. Nylas syncs drafts to the provider's Draft folder, if possible.
  • Send email message without creating draft: This method is ideal for sending a small number of email messages without saving them as drafts first. Nylas syncs email messages to the provider's Sent folder, if possible.

In both cases, the sending operation is synchronous (meaning Nylas sends items one at a time) and the request blocks until the submission either succeeds or fails. If the submission fails, the Nylas Send API does not automatically try to send the email message again. For more information, see Deliverability for drafts and Send endpoint.

When you make a Send Message request, Nylas connects to the provider to send the message as the user. Because of this, providers see the activity as the user sending a message, rather than an external platform making the request on the user's behalf.

Email messages sent through Nylas have very high deliverability, but might be subject to rate-limiting and abuse detection from the provider. See Improve email deliverability for more information and a list of best practices.

Create and send a draft

If you want to prepare an email message that doesn't need to be sent immediately, you can create a draft and send it later. When you create a draft with Nylas, it's synced with the provider. You can access it and make updates as long as it isn't deleted.

To create a draft in Nylas v3, make a Create Draft request and include any relevant information, or use the Nylas SDKs. All parameters for a Create Draft request are optional. If you make the request with no parameters, Nylas creates a draft with no content.

curl --request POST \
--url https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/drafts \
--header 'Authorization: Bearer <NYLAS_API_KEY>' \
--header 'Content-Type: application/json' \
--data '{
"subject": "From Nylas",
"to": [
{
"email": "dorothy@example.com",
"name": "Dorothy Vaughan"
}
],
"cc": [
{
"email": "George Washington Carver",
"name": "carver@example.com"
}
],
"bcc": [
{
"email": "Albert Einstein",
"name": "al@example.com"
}
],
"reply_to": [
{
"email": "skwolek@example.com",
"name": "Stephanie Kwolek"
}
],
"body": "This email was sent using the Nylas email API. Visit https://nylas.com for details.",
"tracking_options": {
"opens": true,
"links": true,
"thread_replies": true,
"label": "hey just testing"
}
}'
import 'dotenv/config'
import Nylas from 'nylas'

const NylasConfig = {
apiKey: process.env.NYLAS_API_KEY,
apiUri: process.env.NYLAS_API_URI,
}

const nylas = new Nylas(NylasConfig)
const identifier = process.env.NYLAS_GRANT_ID

const createDraft = async () => {
try {
const draft = {
subject: "Your Subject Here",
to: [{ name: "Recipient Name", email: "recipient@example.com" }],
body: "Your email body here.",
}

const createdDraft = await nylas.drafts.create({
identifier,
requestBody: draft
})

console.log('Draft created:', createdDraft)

} catch (error) {
console.error('Error creating draft:', error)
}
}

createDraft()
import os
import sys
from nylas import Client
from nylas import utils

nylas = Client(
"<NYLAS_API_KEY>",
"<NYLAS_API_URI")
)

grant_id = "<NYLAS_GRANT_ID>"
email = "<EMAIL>"

attachment = utils.file_utils.attach_file_request_builder("Nylas_Logo.png")

draft = nylas.drafts.create(
grant_id,
request_body={
"to": [{ "name": "Name", "email": email }],
"reply_to": [{ "name": "Name", "email": email }],
"subject": "Your Subject Here",
"body": "Your email body here.",
"attachments": [attachment]
}
)

print(draft)
require 'nylas'

nylas = Nylas::Client.new(api_key: '<NYLAS_API_KEY>')
file = Nylas::FileUtils.attach_file_request_builder("RubyLogo.png")

request_body = {
subject: "From Nylas",
body: 'This email was sent using the ' +
'Nylas Email API. ' +
'Visit https://nylas.com for details.',
to: [{ name: "Nylas",
email: "swag@example.com"}],
cc: [{ email: 'dorothy@example.com',
name: 'Dorothy Vaughan' }],
bcc: [{ email: 'Lamarr@example.com',
name: 'Hedy Lamarr' }],
attachments: [file]
}

draft, _ = nylas.drafts.create(identifier: "<NYLAS_GRANT_ID>", request_body: request_body)

puts "Draft \"#{draft[:subject]}\" was created with ID: #{draft[:id]}"
import com.nylas.NylasClient;
import com.nylas.models.*;
import com.nylas.util.FileUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class CreateDraft {
public static void main(String[] args) throws NylasSdkTimeoutError, NylasApiError {
NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();
CreateAttachmentRequest attachment = FileUtils.attachFileRequestBuilder("src/main/java/JavaLogo.png");

List<CreateAttachmentRequest> request = new ArrayList<>();
request.add(attachment);

CreateDraftRequest requestBody = new CreateDraftRequest.Builder().
to(Collections.singletonList(new EmailName("swag@example.com", "Nylas"))).
cc(Collections.singletonList(new EmailName("dorothy@example.com", "Dorothy Vaughan"))).
bcc(Collections.singletonList(new EmailName("Lamarr@example.com", "Hedy Lamarr"))).
subject("With Love, from Nylas").
body("This email was sent using the Nylas Email API. Visit https://nylas.com for details.").
attachments(request).
build();

Response<Draft> drafts = nylas.drafts().create("<NYLAS_GRANT_ID>", requestBody);

System.out.println("Draft " + drafts.getData().getSubject() + " was created with ID " + drafts.getData().getId());
}
}
import com.nylas.NylasClient
import com.nylas.models.*
import com.nylas.util.FileUtils

fun main(args: Array<String>) {
val nylas: NylasClient = NylasClient(apiKey = "<NYLAS_API_KEY>")
val attachment: CreateAttachmentRequest = FileUtils.attachFileRequestBuilder("src/main/kotlin/Kotlin_Logo.png")

val requestBody = CreateDraftRequest(
to = listOf(EmailName("swag@example.com", "Nylas")),
cc = listOf(EmailName("dorothy@example.com", "Dorothy Vaughan")),
bcc = listOf(EmailName("Lamarr@example.com", "Hedy Lamarr")),
subject = "With Love, from Nylas",
body = "This email was sent using the Nylas Email API. Visit https://nylas.com for details.",
attachments = listOf(attachment)
)

val draft = nylas.drafts().create("<NYLAS_GRANT_ID>", requestBody).data

print("Draft " + draft.subject + " was created with ID: " + draft.id)
}

When you're ready, you can send the draft by making a Send Draft request or by using the SDKs, as in the examples below.

import 'dotenv/config'
import Nylas from 'nylas'

const NylasConfig = {
apiKey: process.env.NYLAS_API_KEY,
apiUri: process.env.NYLAS_API_URI,
}

const nylas = new Nylas(NylasConfig)
const identifier = process.env.NYLAS_GRANT_ID
const draftId = process.env.DRAFT_ID

const sendDraft = async () => {
try {
const sentMessage = await nylas.drafts.send({ identifier, draftId })
console.log('Draft sent:', sentMessage)
} catch (error) {
console.error('Error sending draft:', error)
}
}

sendDraft()
from dotenv import load_dotenv
load_dotenv()

import os
import sys
from nylas import Client

nylas = Client(
os.environ.get('NYLAS_API_KEY'),
os.environ.get('NYLAS_API_URI')
)

grant_id = os.environ.get("NYLAS_GRANT_ID")
draft_id = os.environ.get("DRAFT_ID")

draft = nylas.drafts.send(
grant_id,
draft_id
)

print(draft)
require 'nylas'

nylas = Nylas::Client.new(api_key: '<NYLAS_API_KEY>')
draft, _ = nylas.drafts.send(identifier: "<NYLAS_GRANT_ID>", draft_id: "{DRAFT_ID}")

puts "Draft \"#{draft[:subject]}\" was sent with ID #{draft[:id]}"
import com.nylas.NylasClient;
import com.nylas.models.*;

public class SendDraft {
public static void main(String[] args) throws NylasSdkTimeoutError, NylasApiError {
NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();
Response<Message> draft = nylas.drafts().send("<NYLAS_GRANT_ID>", "<DRAFT_ID>");

System.out.println(draft.getData());
}
}
import com.nylas.NylasClient

fun main(args: Array<String>) {
val nylas: NylasClient = NylasClient(apiKey = "<NYLAS_API_KEY>")
val draft = nylas.drafts().send("<NYLAS_GRANT_ID>", "<DRAFT_ID>")

print(draft.data)
}

Create and send an email message

If you want to create and send an email message immediately, you can do so without creating a draft.

To create and send an email message in Nylas v3, make a Send Message request. You can also create and send an email message using the Nylas SDKs, as in the examples below.

app.get("/nylas/send-email", async (req, res) => {
try {
const sentMessage = await nylas.messages.send({
identifier: process.env.USER_GRANT_ID,
requestBody: {
to: [{ name: "Name", email: process.env.EMAIL }],
replyTo: [{ name: "Name", email: process.env.EMAIL }],
replyToMessageId: "<MESSAGE_ID>",
subject: "Your Subject Here",
body: "Your email body here.",
},
});

res.json(sentMessage);
} catch (error) {
console.error("Error sending email:", error);
}
});
import os
import sys
from nylas import Client
from nylas import utils

nylas = Client(
"<NYLAS_API_KEY>",
"<NYLAS_API_URI>"
)

grant_id = "<NYLAS_GRANT_ID>"
email = "<EMAIL>"

attachment = utils.file_utils.attach_file_request_builder("Nylas_Logo.png")

message = nylas.messages.send(
grant_id,
request_body={
"to": [{ "name": "Name", "email": email }],
"reply_to": [{ "name": "Name", "email": email }],
"reply_to_message_id": "<MESSAGE_ID>",
"subject": "Your Subject Here",
"body": "Your email body here.",
"attachments": [attachment]
}
)

print(message)
require 'nylas'

nylas = Nylas::Client.new(api_key: '<NYLAS_API_KEY>')
file = Nylas::FileUtils.attach_file_request_builder("Ruby_Logo.png")

request_body = {
subject: "With Love, from Nylas",
body: "This email was sent using the <b>Ruby SDK</b> for the Nylas Email API. Visit <a href='https://nylas.com'>Nylas.com</a> for details.",
to: [{name: "Nylas", email: "swag@example.com"}],
attachments: [file]
}

email = nylas.messages.send(identifier: "<NYLAS_GRANT_ID>", request_body: request_body)

puts email
import com.nylas.NylasClient;
import com.nylas.models.*;
import com.nylas.util.FileUtils;
import java.util.ArrayList;
import java.util.List;

public class SendEmails {
public static void main(String[] args) throws NylasSdkTimeoutError, NylasApiError {
NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();

List<EmailName> emailNames = new ArrayList<>();
emailNames.add(new EmailName("swag@example.com", "Nylas"));

CreateAttachmentRequest attachment = FileUtils.attachFileRequestBuilder("src/main/java/JavaLogo.png");
List<CreateAttachmentRequest> request = new ArrayList<>();
request.add(attachment);

SendMessageRequest requestBody = new SendMessageRequest.Builder(emailNames).
subject("With Love, from Nylas").
body("This email was sent using the <b>Java SDK</b> for the Nylas Email API." +
" Visit <a href='https://nylas.com'>Nylas.com</a> " +
"for details.").
attachments(request).
build();

Response<Message> email = nylas.messages().send("<NYLAS_GRANT_ID>", requestBody);

System.out.println(email.getData());
}
}
import com.nylas.NylasClient
import com.nylas.models.*
import com.nylas.util.FileUtils

fun main(args: Array<String>) {
val nylas: NylasClient = NylasClient(apiKey = dotenv["NYLAS_API_KEY"])
val attachment: CreateAttachmentRequest = FileUtils.attachFileRequestBuilder("src/main/kotlin/Kotlin_Logo.png")
val emailNames : List<EmailName> = listOf(EmailName("swag@example.com", "Nylas"))

val requestBody : SendMessageRequest = SendMessageRequest.
Builder(emailNames).
subject("With Love, from Nylas").
body("This email was sent using the Nylas email API. Visit https://nylas.com for details.").
attachments(listOf(attachment)).
build()

val email = nylas.messages().send(dotenv["NYLAS_GRANT_ID"], requestBody)

print(email.data)
}

Draft deliverability and the Send endpoint

Send operations are synchronous (meaning Nylas sends items one at a time), and the request blocks until the submission succeeds or fails. If the request fails, the Nylas Send API does not automatically try to send the email message again.

💡 A successful request to the Send endpoint can sometimes take up to two minutes for self-hosted Exchange accounts, though the average send time is approximately two seconds. To ensure that you receive a response from Nylas, set the maximum timeout to 150 seconds.

Nylas recommends that you apply a backoff strategy when the Send API returns HTTP 503 errors. Your application might need to wait between 10–20 minutes, or else SMTP servers might continue to refuse connections for the affected end user.

For information on the number of email messages you can send per day, see the Provider rate limits documentation. If large-volume sending continues to fail for your application, Nylas recommends you switch to a transactional sending service (for example, Mailgun, Sendgrid, Mandrill, or Amazon SES).

Bounce detection

📝 Note: Bounce detection is available for Google, Microsoft Graph, iCloud, and Yahoo only.

In v3, Nylas monitors for and notifies you when an end user gets an email message bounce notification. Bounce notifications are sent by an email recipient's provider when the message can't be delivered, and usually include a detailed error message. When an end user receives a notification that a message bounced, Nylas scans it and grabs the cause from the error message.

Email messages can bounce for a variety of reasons, and can be considered either "soft" bounces (those with a temporary root cause, like the recipient's inbox being full) or "hard" bounces (those with a permanent root cause, like the recipient's email address no longer exists). Currently, v3 supports hard bounces only, and Nylas publishes mailbox_unavailable and domain_not_found bounces. For more information about bounce detection, see Nylas' message.bounce_detected notification schema and Soft vs. Hard Bounce - what's the difference? on the Nylas blog.

ℹī¸ Bounce detection is available for Free, Core, and Plus plans. Available for demo purposes in the Free-tier Sandbox. Not available for Calendar-only plans.

The email message ID header

Sending an email using the Nylas Email API creates a unique message_id_header in the sender's database, similar to the example below.

4ottpfaje0kqx8iagoih0h3tp-0@mailer.nylas.com   

This value is required for the provider's SMTP server, and is part of the standard protocol when using Nylas as an email client. The header is visible only on the sender's database, and is not an email object that you can use or update.

The provider's SMTP server might modify this value during the sending process. Nylas recommends you avoid using this message_id_header with the @mailer.nylas.com domain for email configuration.

Override sender display name

When you send email messages using Nylas, you can set the sender's display name by modifying the from.name parameter in your request, as in the following example.

⚠ī¸ Some Exchange servers might ignore From headers when sending email messages, and instead default to the sender's display name. When this happens, Nylas cannot change the sender's display name. Instead, the end user must change it in their account settings.

curl --request POST \
--url https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/messages/send \
--header 'Authorization: Bearer <NYLAS_API_KEY>' \
--header 'Content-Type: application/json' \
--data '{
"subject": "Reaching out with Nylas",
"to": [{
"name": "John Doe",
"email": "john.doe@example.com"
}],
"from": [{
"name": "Nyla",
"email": "nyla@example.com"
}]
}'

If you don't include the from field when you send an email message, Nylas uses the account's default display name.

Limitations for sending messages

Microsoft Graph and iCloud do not support the List-Unsubscribe-Post or List-Unsubscribe headers. Because of this, Nylas can't support these headers for messages sent from Microsoft Graph and iCloud accounts.

What's next?

Now that you know how to send email messages with Nylas, you can learn about email message tracking and scheduling email messages to be sent later.

You can also read the following blog posts for a deeper dive: