Only show these results:

Email API Quickstart: read and send email messages

Welcome to Nylas! 👋 We’re happy you’re here.

In this guide you'll build a sample web app that connects to your email account. You can then read your email and send new email messages from the app.

A sample web app showing JSON details about a set of email messages. The web app has two display options: raw and parsed.

This Quickstart guide is for any developer who...

  • Wants to learn the basics of Nylas by getting a minimal project up and running.
  • Is comfortable with one of the Nylas SDK languages: Node.js, Python, Ruby, Java, or Kotlin.
  • Wants to learn by doing and save the details for later.

What to expect

This guide will walk you through how to...

  1. Set up and configure your Nylas project.
  2. Bootstrap your application.
  3. Implement OAuth 2.0 with Nylas.
  4. Use the Nylas Email API to read and send email messages.

When you're done, you’ll understand the general process of building with Nylas. From there, we’ll point you to some resources to learn more and try out other APIs.

The complete code for this Quickstart guide is available on GitHub. You can clone the repo and run the app to see it in action for the Nylas SDK language of your choice: Node.js, Python, Ruby, Java, or Kotlin.

Let’s get started!

Before you begin

Be sure to have the following ready before you begin:

  • Your language’s development environment installed.
  • A code editor.
  • A terminal.
  • A web browser.

Got all of that? You’re ready to go!

Set up your Nylas account

This section is all about what we need to do before we start coding.

Create a Nylas account

Nylas offers a free Sandbox account where you can prototype and test the Nylas APIs. Sign up to create a Nylas account.

Create a Nylas Sandbox application

Go to the Nylas v3 Dashboard and create a new application.

When you first log in to your v3 Dashboard account, your organization is empty. Click Create a new application to get started.

Set an Application name and Description, then select your preferred data residency location, and tag the environment as Sandbox. If you use the Sandbox, you can skip setting up your own service connector during the Quickstart.

The Nylas v3 Dashboard showing the create a new application dialog. The form is filled out with My Sandbox as the title, and the selected application type is Sandbox.

Get your application credentials

To use the Nylas API, you need your Nylas application’s client ID and an API key, which you can get from the Dashboard. You'll save these credentials in your code environment as NYLAS_CLIENT_ID and NYLAS_API_KEY.

You can find your Nylas client ID on the Dashboard Overview page.

A branch new Nylas Sandbox application showing its client ID on the front page.

Next, generate an API key:

  1. In your Sandbox application click API keys in the left navigation.
  2. Click Generate new key.
  3. Enter a name for the key (something like "demo" or "test" is a good place to start) and an expiration date (for this walkthrough, you can leave the default date).
  4. Click Generate key, then copy the API key secret that appears and save it to your secrets manager.

You'll use this value as your NYLAS_API_KEY in your code.

A freshly generated API key showing its secret for the first and only time. It is a fake API key secret for those of you who read this text.

Bootstrap your app

This section walks you through setting up a basic local project using your preferred language. Nothing here is Nylas-specific — we're just getting the server scaffold ready.

Create a local project

First, create a local project for testing. You can copy and paste the following commands directly into your terminal or command line tool.

npm init -y
touch index.js
touch index.py   
touch index.rb   
mvn archetype:generate -DgroupId=com.nylas -DartifactId="quickstart"
-DarchetypeArtifactId=maven-archetype-quickstart
-DinteractiveMode=false
mvn archetype:generate -DgroupId=com.nylas -DartifactId="quickstart"
-DarchetypeArtifactId=maven-archetype-quickstart
-DinteractiveMode=false

rm -r main
mkdir kotlin

Create your ENV file

Next, create an .env file. You'll use this file to store credentials and constants that you want to avoid including in your source code.

Your Nylas API URI should be either https://api.us.nylas.com if you're using the U.S. region, or https://api.eu.nylas.com if you're using the E.U. region.

# .env
NYLAS_CLIENT_ID=ADD_YOUR_NYLAS_CLIENT_ID_HERE
NYLAS_API_KEY=ADD_YOUR_NYLAS_API_KEY_HERE
NYLAS_API_URI=(pick one: https://api.us.nylas.com or https://api.eu.nylas.com)

# Python
NYLAS_CLIENT_ID="ADD_YOUR_NYLAS_CLIENT_ID_HERE"
NYLAS_API_KEY="ADD_YOUR_NYLAS_API_KEY_HERE"
NYLAS_API_URI="(pick one: https://api.us.nylas.com or https://api.eu.nylas.com)"

📝 Note: Your .env file contains important credentials, and you should never commit it to the repository. Add your .env to your .gitignore list so you don't accidentally commit it to the repository. See the official Git documentation for more details.

Install your dependencies

Install the Nylas SDK of your choice, along with the dependencies for this project.

npm install dotenv express nylas   
pip3 install python-dotenv nylas -U flask   
gem install dotenv nylas sinatra   
<dependency>
<groupId>com.sparkjava</groupId>
<artifactId>spark-core</artifactId>
<version>2.9.4</version>
</dependency>
<dependency>
<groupId>io.github.cdimascio</groupId>
<artifactId>dotenv-java</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>com.nylas.sdk</groupId>
<artifactId>nylas</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
<groupId>com.sparkjava</groupId>
<artifactId>spark-kotlin</artifactId>
<version>1.0.0-alpha</version>
</dependency>
<dependency>
<groupId>com.nylas.sdk</groupId>
<artifactId>nylas</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>io.github.cdimascio</groupId>
<artifactId>dotenv-kotlin</artifactId>
<version>6.4.1</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>

Configure the Nylas SDK

Set up the Nylas SDK, using some of the environment variables from your .env file.

import "dotenv/config";
import express from "express";
import Nylas from "nylas";

const config = {
clientId: process.env.NYLAS_CLIENT_ID,
callbackUri: "http://localhost:3000/oauth/exchange",
apiKey: process.env.NYLAS_API_KEY,
apiUri: process.env.NYLAS_API_URI,
};

const nylas = new Nylas({
apiKey: config.apiKey,
apiUri: config.apiUri, // "https://api.us.nylas.com" or "https://api.eu.nylas.com"
});

const app = express();
const port = 3000;

// Start the server
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
from dotenv import load_dotenv
import os
from nylas import Client
from flask import Flask, request, redirect, url_for, session, jsonify
from flask_session.__init__ import Session
from nylas.models.auth import URLForAuthenticationConfig
from nylas.models.auth import CodeExchangeRequest
from datetime import datetime, timedelta

load_dotenv()

app = Flask(__name__)
app.config["SESSION_PERMANENT"] = False
app.config["SESSION_TYPE"] = "filesystem"
Session(app)

nylas = Client(
api_key = os.environ.get("NYLAS_API_KEY"),
api_uri = os.environ.get("NYLAS_API_URI"),
)

if __name__ == "__main__":
app.run()
require 'nylas'
require 'dotenv/load'
require 'sinatra'

set :show_exceptions, :after_handler
enable :sessions

error 404 do
'No authorization code returned from Nylas'
end

error 500 do
'Failed to exchange authorization code for token'
end

nylas = Nylas::Client.new(
api_key: ENV['NYLAS_API_KEY'],
api_uri: ENV['NYLAS_API_URI']
)
import java.time.*;
import java.time.temporal.ChronoUnit;
import java.util.*;
import static spark.Spark.*;
import com.google.gson.Gson;
import com.nylas.NylasClient;
import com.nylas.models.*;
import com.nylas.models.Calendar;
import io.github.cdimascio.dotenv.Dotenv;

public class quickstart_java {
public static void main(String[] args) {
Dotenv dotenv = Dotenv.load();
NylasClient nylas = new NylasClient.Builder(dotenv.get("NYLAS_API_KEY")).apiUri(dotenv.get("NYLAS_API_URI")).build();
}
}
import com.nylas.NylasClient
import com.nylas.models.*
import io.github.cdimascio.dotenv.dotenv
import com.google.gson.Gson;
import spark.kotlin.Http
import spark.kotlin.ignite
import java.time.LocalDate
import java.time.ZoneId
import java.time.temporal.ChronoUnit

fun main(args: Array<String>) {
val dotenv = dotenv()

val nylas = NylasClient(
apiKey = dotenv["NYLAS_API_KEY"],
apiUri = dotenv["NYLAS_API_URI"]
)

val http: Http = ignite()
}

Next up, you’ll log an end user into your application.

Set up user auth using Nylas

This section will show you how to implement OAuth 2.0 using your chosen Nylas SDK. By the end of this section, you’ll have a user logged into your app!

Register an authentication callback URI

Next, you will register a callback URI with Nylas, which Nylas will redirect the user to when the authentication flow completes.

For this walkthrough, you are using a local development environment, so your URI will probably include localhost.

  1. In your Sandbox application, click Hosted Authentication in the left navigation, and click the Callback URI tab.
  2. Click Add a callback URI, and enter your application's callback URI.

Hosted authentication screen showing the Callback URIs tab, and a freshly added entry for a localhost callback URI.

In the example above, we show an endpoint /oauth/exchange that points to our local development environment hosted at http://localhost:9000. These values are arbitrary and can be set to whatever you like, as long as they match the callback URI you use in your code.

⚠️ You might want to use a different port number when you register the callback URI. For this walkthrough, you should use the conventional port that your chosen language and framework uses.

Redirect your user to the provider’s login screen

The first step of the authentication process is to start an authorization request. Usually, this is a button or link in your application that the end user clicks.

To initiate the OAuth flow, you must redirect the user to a given provider (for example Google, Microsoft) using a configured URL.

Each Nylas SDK offers a way to build this URL.

// Route to initialize authentication
app.get("/nylas/auth", (req, res) => {
const authUrl = nylas.auth.urlForOAuth2({
clientId: config.clientId,
redirectUri: config.callbackUri,
});

res.redirect(authUrl);
});
@app.route("/nylas/auth", methods=["GET"])
def login():
if session.get("grant_id") is None:
config = URLForAuthenticationConfig({"client_id": os.environ.get("NYLAS_CLIENT_ID"),
"redirect_uri" : "http://localhost:5000/oauth/exchange"})

url = nylas.auth.url_for_oauth2(config)

return redirect(url)
else:
return f'{session["grant_id"]}'
get '/nylas/auth' do
config = {
client_id: ENV['NYLAS_CLIENT_ID'],
provider: 'google',
redirect_uri: 'http://localhost:4567/oauth/exchange',
login_hint: '[email protected]',
access_type: 'offline'
}

url = nylas.auth.url_for_oauth2(config)
redirect url
end
get("/nylas/auth", (request, response) -> {
List<String> scope = new ArrayList<>();
scope.add("https://www.googleapis.com/auth/calendar");

UrlForAuthenticationConfig config = new UrlForAuthenticationConfig(dotenv.get("NYLAS_CLIENT_ID"),
"http://localhost:4567/oauth/exchange",
AccessType.ONLINE,
AuthProvider.GOOGLE,
Prompt.DETECT,
scope,
true,
"sQ6vFQN",
"[email protected]");

String url = nylas.auth().urlForOAuth2(config);
response.redirect(url);

return null;
});
http.get("/nylas/auth") {
val scope = listOf("https://www.googleapis.com/auth/calendar", "https://www.googleapis.com/auth/calendar.events")

val config : UrlForAuthenticationConfig = UrlForAuthenticationConfig(
dotenv["NYLAS_CLIENT_ID"],
"http://localhost:4567/oauth/exchange",
AccessType.ONLINE,
AuthProvider.GOOGLE,
Prompt.DETECT,
scope,
true,
"sQ6vFQN",
"[email protected]")

val url = nylas.auth().urlForOAuth2(config)

response.redirect(url)
}

Nylas offers several ways to customize your OAuth flow. For this guide, we’ve kept it simple, but you can learn more in the Nylas API documentation.

Receive a callback from Nylas with the user’s grant ID

Each provider displays the consent and approval steps differently, and they are only visible to the end user.

In all cases: the user authenticates, and either accepts or declines the scopes your project requested. If they accept, you receive a code from Nylas that you can exchange for a "grant ID", which represents the logged in user with all the scopes they accepted.

When Nylas calls your redirect URI, you then exchange the code using the Nylas SDKs, as in the following examples:

// callback route Nylas redirects to
app.get("/oauth/exchange", async (req, res) => {
console.log("Received callback from Nylas");
const code = req.query.code;

if (!code) {
res.status(400).send("No authorization code returned from Nylas");
return;
}

const codeExchangePayload = {
clientSecret: config.apiKey,
clientId: config.clientId,
redirectUri: config.callbackUri,
code,
};

try {
const response = await nylas.auth.exchangeCodeForToken(codeExchangePayload);
const { grantId } = response;

// NB: This stores in RAM
// In a real app you would store this in a database, associated with a user
process.env.NYLAS_GRANT_ID = grantId;

res.json({ message: "OAuth2 flow completed successfully for grant ID: " + grantId });
} catch (error) {
res.status(500).send("Failed to exchange authorization code for token");
}
});
@app.route("/oauth/exchange", methods=["GET"])
def authorized():
if session.get("grant_id") is None:
code = request.args.get("code")

exchangeRequest = CodeExchangeRequest({"redirect_uri": "http://localhost:5000/oauth/exchange",
"code": code, "client_id": os.environ.get("NYLAS_CLIENT_ID")})

exchange = nylas.auth.exchange_code_for_token(exchangeRequest)
session["grant_id"] = exchange.grant_id

return redirect(url_for("login"))
get '/oauth/exchange' do
code = params[:code]
status 404 if code.nil?

begin
response = nylas.auth.exchange_code_for_token({
client_id: ENV['NYLAS_CLIENT_ID'],
redirect_uri: 'http://localhost:4567/oauth/exchange',
code: code})
rescue StandardError
status 500
else
response[:grant_id]
response[:email]
session[:grant_id] = response[:grant_id]
end
end
get("/oauth/exchange", (request, response) -> {
String code = request.queryParams("code");

if(code == null) { response.status(401);}
assert code != null;

CodeExchangeRequest codeRequest = new CodeExchangeRequest(
"http://localhost:4567/oauth/exchange",
code,
dotenv.get("NYLAS_CLIENT_ID"),
null,
null);

try {
CodeExchangeResponse codeResponse = nylas.auth().exchangeCodeForToken(codeRequest);
request.session().attribute("grant_id", codeResponse.getGrantId());

return "%s".formatted(codeResponse.getGrantId());
} catch(Exception e) {
return "%s".formatted(e);
}
});
http.get("/oauth/exchange") {
val code : String = request.queryParams("code")

if(code == "") { response.status(401) }

val codeRequest : CodeExchangeRequest = CodeExchangeRequest(
"http://localhost:4567/oauth/exchange",
code,
dotenv["NYLAS_CLIENT_ID"],
null,
null
)

try {
val codeResponse : CodeExchangeResponse = nylas.auth().exchangeCodeForToken(codeRequest)
request.session().attribute("grant_id",codeResponse.grantId)

codeResponse.grantId
} catch (e : Exception) {
e.toString()
}
}

When this process completes successfully, Nylas marks the end user's grant as verified and sends you their grant ID and email address.

As long as authentication succeeded, you can stop the OAuth process here, record the grant ID created for the user, and continue using your API key to make requests on behalf of this grant, as shown in the next section.

Use the Nylas Email API

This section is the fun part! Now that you've authenticated your user, you can use the Nylas Email API to read and send email messages.

Read email messages

First up, let's read the email messages from the authenticated user's inbox.

app.get("/nylas/recent-emails", async (req, res) => {
try {
const identifier = process.env.USER_GRANT_ID;
const messages = await nylas.messages.list({
identifier,
queryParams: {
limit: 5,
},
});

res.json(messages);
} catch (error) {
console.error("Error fetching emails:", error);
}
});
@app.route("/nylas/recent-emails", methods=["GET"])

def recent_emails():
query_params = {"limit": 5}

try:
messages, _, _ = nylas.messages.list(session["grant_id"], query_params)

return jsonify(messages)
except Exception as e:
return f'{e}'
get '/nylas/recent-emails' do
query_params = { limit: 5 }
messages, = nylas.messages.list(identifier: session[:grant_id], query_params: query_params)

messages.to_json
rescue StandardError => e
e.to_s
end
get("/nylas/recent-emails", (request, response) -> {
try {
ListMessagesQueryParams queryParams = new ListMessagesQueryParams.Builder().limit(5).build();

ListResponse<Message> emails = nylas.messages().list(request.session().attribute("grant_id"),
queryParams);

Gson gson = new Gson();

return (gson.toJson(emails.getData()));
} catch (Exception e) {
return "%s".formatted(e);
}
});
http.get("/nylas/recent-emails") {
try {
val queryParams = ListMessagesQueryParams.Builder().limit(5).build()

val emails = nylas.messages().list(request.session().attribute("grant_id"),
queryParams)

val gson = Gson()

gson.toJson(emails.data)
} catch (e : Exception) {
e.toString()
}
}

Send email messages

Next, we'll send an email message using the Nylas Email API. In all cases, the identifier is the NYLAS_GRANT_ID you received when you authenticated the end user - this is the account you're sending from!

For these code samples, if you want to receive the email you're about to send, be sure to replace any email properties with your own email address.

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 }],
subject: "Your Subject Here",
body: "Your email body here.",
},
});

res.json(sentMessage);
} catch (error) {
console.error("Error sending email:", error);
}
});
@app.route("/nylas/send-email", methods=["GET"])

def send_email():
try:
body = {"subject" : "Your Subject Here",
"body":"Your Email Here",
"reply_to":[{"name": "Name", "email": os.environ.get("EMAIL")}],
"to":[{"name": "Name", "email": os.environ.get("EMAIL")}]}

message = nylas.messages.send(session["NYLAS_GRANT_ID"], request_body = body).data

return jsonify(message)
except Exception as e:
return f'{e}'
get '/nylas/send-email' do
request_body = {
subject: 'Your Subject Here',
body: 'Your Email Here',
to: [{ name: 'Name', email: ENV['EMAIL'] }],
reply_to: [{ name: 'Name', email: ENV['EMAIL'] }]
}

email, = nylas.messages.send(identifier: session[:grant_id], request_body: request_body)

email.to_json
rescue StandardError => e
e.to_s
end
get("/nylas/send-email", (request, response) -> {
try {
List<EmailName> emailNames = new ArrayList<>();
emailNames.add(new EmailName(dotenv.get("EMAIL"), "Name"));

SendMessageRequest requestBody = new SendMessageRequest.Builder(emailNames).
replyTo(emailNames).
subject("Your Subject Here").
body("Your email body here").
build();

Response<Message> email = nylas.messages().send(dotenv.get("NYLAS_GRANT_ID"), requestBody);
Gson gson = new Gson();

return gson.toJson(email.getData());
} catch (Exception e) {
return "%s".formatted(e);
}
});
http.get("/nylas/send-email") {
try {
val emailNames : List<EmailName> = listOf(EmailName(dotenv["EMAIL"], "Name"))

val requestBody : SendMessageRequest = SendMessageRequest.Builder(emailNames).
replyTo(listOf(EmailName(dotenv["EMAIL"], "Name"))).
subject("Your Subject Here").
body("Your email body here").
build()

val email = nylas.messages().send(request.session().attribute("NYLAS_GRANT_ID"),
requestBody)

val gson = Gson()

gson.toJson(email.data)
} catch (e : Exception) {
e.toString()
}
}

Next steps

Congrats! 🎉 In this Quickstart guide, you built a simple web app, set up OAuth, and started working with email messages in Nylas.

If you'd like to see the complete code for this guide, you can find it on GitHub for the Nylas SDK language of your choice: Node.js, Python, Ruby, Java, or Kotlin.

Want to try something similar with a calendar? Check out the Calendar API Quickstart guide.

The links below are further reading as you continue your journey to Nylas greatness: