Send messages with Nylas
Nylas offers multiple ways to send messages. This page describes how to choose the best method for your project, how to create and send a draft, and how to send a message without creating a draft.
Choose how to send messages
Nylas offers two different ways to send messages:
- Create and send a draft: This method is ideal for preparing messages that you don't need to send immediately. Nylas syncs drafts to the provider's Draft folder, if possible.
- Send message without creating draft: This method is ideal for sending a small number of messages without saving them as drafts first. Nylas syncs 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, Nylas does not automatically try to send the 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.
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 a message that you don't need to send 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. 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'
# Initialize Nylas client
nylas = Nylas::Client.new(
api_key: "<NYLAS_API_KEY>"
)
file = Nylas::FileUtils.attach_file_request_builder("Nylas_Logo.png")
request_body = {
subject: "From Nylas",
body: 'This email was sent using the ' +
'Nylas email API. ' +
'Visit https://nylas.com for details.',
to: [{ name: "Dorothy Vaughan",
email: "dorothy@example.com"}],
cc: [{ name: "George Washington Carver",
email: "carver@example.com"}],
bcc: [{ name: "Albert Einstein",
email: "al@example.com"}],
reply_to: [{ name: "Stephanie Kwolek",
email: "skwolek@example.com"}],
tracking_options: {label: "hey just testing",
opens: true,
links: true,
thread_replies: true},
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/Nylas_Logo.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(dotenv.get("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/Nylas_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(dotenv["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.
curl --request POST \
--url https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/drafts/<DRAFT_ID> \
--header 'Accept: application/json, application/gzip' \
--header 'Authorization: Bearer <NYLAS_API_KEY>' \
--header 'Content-Type: application/json' \
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>")
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)
}
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());
}
}
Create and send a message
If you want to create and send a message immediately, make a Send Message request or use the Nylas SDKs.
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": "Hey Reaching Out with Nylas",
"body": "Hey I would like to track this link <a href='https://espn.com'>My Example Link</a>",
"to": [
{
"name": "John Doe",
"email": "john.doe@example.com"
}
],
"tracking_options": {
"opens": true,
"links": true,
"thread_replies": true,
"label": "hey just testing"
}
}'
import { createFileRequestBuilder } from 'utils';
app.get("/nylas/send-email", async (req, res) => {
try {
const file = createFileRequestBuilder("Nylas_Logo.png")
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.",
attachments: [file]
},
});
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)
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)
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/Nylas_Logo.png")
val options = TrackingOptions("hey just testing", true, true, true)
val emailNames : List<EmailName> = listOf(EmailName("john.doe@example.com",
"John Doe"))
val requestBody : SendMessageRequest =
SendMessageRequest.Builder(emailNames).
subject("Hey Reaching Out with Nylas").
body("Hey I would like to track this link <a href='https://espn.com'>My Example Link</a>").
trackingOptions(options).
attachments(listOf(attachment)).
build()
val email = nylas.messages().send("<NYLAS_GRANT_ID>",
requestBody)
print(email.data)
}
import com.nylas.NylasClient;
import com.nylas.models.*;
import java.util.ArrayList;
import java.util.List;
import com.nylas.util.FileUtils;
public class SendEmails {
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/Nylas_Logo.png");
List<CreateAttachmentRequest> request = new ArrayList<>();
request.add(attachment);
List<EmailName> emailNames = new ArrayList<>();
emailNames.add(new EmailName("john.doe@example.com",
"John Doe"));
TrackingOptions options =
new TrackingOptions("hey just testing", true, true, true);
SendMessageRequest requestBody =
new SendMessageRequest.Builder(emailNames).
trackingOptions(options).
subject("Hey Reaching Out with Nylas").
body("Hey I would like to track this link <a href='https://espn.com'>My Example Link</a>.").
attachments(request).
build();
Response<Message> email =
nylas.messages().send("<NYLAS_GRANT_ID>", requestBody);
System.out.println(email.getData());
}
}
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, Nylas does not automatically try to send the 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 about two seconds. To ensure that you receive a response from Nylas, set the timeout to 150 seconds.
Nylas recommends that you apply a backoff strategy when you receive 503
errors. Your application might need to wait between 10â20 minutes, or else SMTP servers might continue to refuse connections for the affected user.
For information on the number of 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
Nylas monitors for and notifies you when a user gets a message bounce notification. Bounce notifications are sent by a recipient's provider when the message can't be delivered, and usually include a detailed error message. When a user receives a notification that a message bounced, Nylas scans it and grabs the cause from the error message.
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, Nylas supports hard bounces only, and publishes mailbox_unavailable
and domain_not_found
bounces. For more information about bounce detection, see the message.bounce_detected
notification schema and Soft vs. Hard Bounce - what's the difference? on the Nylas blog.
The message ID header
Sending a message 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 isn't an object that you can use or update.
The provider's SMTP server might change 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 messages using Nylas, you can set the sender's display name by modifying the from.name
parameter in your request.
â ī¸ Some Exchange servers might ignore From headers when sending messages, and instead default to the sender's display name. When this happens, Nylas can't change the sender's display name. Instead, the user needs to 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": "Leyah Miller",
"email": "leyah@example.com"
}],
"from": [{
"name": "Nyla",
"email": "nyla@example.com"
}]
}'
If you don't include the from
field when you send a message, Nylas uses the account's default display name.
Limitations for sending messages
- Microsoft Graph and iCloud don't support the
List-Unsubscribe-Post
orList-Unsubscribe
headers. Because of this, Nylas can't support these headers for messages sent from Microsoft Graph and iCloud accounts. - Some providers change folders immediately after a message sends successfully (for example, moving the message from the Outbox folder to Sent). Because of this, you might receive multiple
message.updated
notifications for a single send request. - Nylas automatically de-duplicates some webhook notifications to avoid spam, so you might receive a
message.updated
notification instead of amessage.created
notification.
What's next?
Now that you know how to send messages with Nylas, you can learn about email message tracking and scheduling messages to be sent later.
You can also read the following blog posts for a deeper dive: