Create grants with IMAP authentication
This page explains how to authenticate end users to your Nylas application using IMAP auth.
🔍 Nylas creates only one grant per email address in each application. If an end user authenticates with your Nylas application using the email address associated with an existing grant, Nylas re-authenticates the grant instead of creating a new one.
IMAP connections don't require a provider auth app, and they don't include calendar functionality.
New options for Yahoo, Exchange, and iCloud users
If you are authenticating Yahoo, Exchange on-prem, or iCloud users, you can either connect them using IMAP, or use the dedicated connectors for those providers. If you connect using IMAP, you can only access email data from the provider, even if the service also provides calendar features.
If you authenticate Yahoo users, you should implement the new v3 Yahoo OAuth method instead of IMAP authentication to improve reliability.
Create a connector
🔍 IMAP does not support the concept of scopes, so don't list any during the authentication process.
Create a connector by making a call to POST /v3/connectors
and setting the provider
to imap
.
{
"name": "Staging App 1",
"provider": "imap"
}
You can also create a connector using the Nylas SDKs, as in the following examples.
import 'dotenv/config'
import Nylas from 'nylas'
const config = {
apiKey: process.env.NYLAS_API_KEY,
apiUri: process.env.NYLAS_API_URI,
}
const nylas = new Nylas(config)
async function createConnector() {
try {
const connector = await nylas.connectors.create({
requestBody: {
name: 'aol',
provider: 'imap',
}
})
console.log('Connector created:', connector)
} catch (error) {
console.error('Error creating connector:', error)
}
}
createConnector()
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')
)
connector = nylas.connectors.create(
request_body={
"name": "aol",
"provider": "imap"
}
)
require 'nylas'
nylas = Nylas::Client.new(api_key: "<NYLAS_API_KEY>")
request_body = {
name: "aol",
provider: "imap",
}
connector = nylas.connectors.create(request_body: request_body)
puts connector
import com.nylas.NylasClient;
import com.nylas.models.*;
public class connector {
public static void main(String[] args) throws NylasSdkTimeoutError, NylasApiError {
NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();
CreateConnectorRequest request = new CreateConnectorRequest.Imap();
nylas.connectors().create(request);
}
}
import com.nylas.NylasClient
import com.nylas.models.CreateConnectorRequest
fun main(args: Array<String>) {
val nylas: NylasClient = NylasClient(apiKey = "<NYLAS_API_KEY>")
val request : CreateConnectorRequest = CreateConnectorRequest.Imap();
nylas.connectors().create(request)
}
Create grants for IMAP users
Nylas v3 offers Hosted OAuth and Custom authentication for the supported IMAP providers.
Hosted OAuth
You can create grants with Hosted OAuth. Learn more about creating grants with Hosted Oauth and an API key and Hosted OAuth and an access token.
You can also start the Hosted auth flow using the Nylas SDKs, as in the examples below.
import 'dotenv/config'
import express from 'express'
import Nylas from 'nylas'
const config = {
clientId: process.env.NYLAS_CLIENT_ID,
clientSecret: process.env.NYLAS_CLIENT_SECRET,
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
})
const app = express()
const port = 3000
// Route to initialize authentication
app.get('/nylas/auth', (req, res) => {
const authUrl = nylas.auth.urlForOAuth2({
clientId: config.clientId,
provider: 'imap',
redirectUri: config.redirectUri,
loginHint: process.env.AOL_IMAP_USERNAME,
state: "state"
})
res.redirect(authUrl)
})
// Callback route Nylas redirects to
app.get('/oauth/exchange', async (req, res) => {
const code = req.query.code
if (!code) {
res.status(400).send('No authorization code returned from Nylas')
return
}
try {
const response = await nylas.auth.exchangeCodeForToken({
clientId: config.clientId,
redirectUri: config.redirectUri,
code,
})
const { grantId } = response
res.status(200)
} catch (error) {
res.status(500).send('Failed to exchange authorization code for token')
}
})
from dotenv import load_dotenv
load_dotenv()
import json
import os
from functools import wraps
from io import BytesIO
from flask import Flask, request, redirect, g
from nylas import Client
nylas = Client(
os.environ.get("NYLAS_CLIENT_ID"),
os.environ.get("NYLAS_API_URI")
)
REDIRECT_CLIENT_URI = 'http://localhost:9000/oauth/exchange'
flask_app = Flask(__name__)
@flask_app.route("/nylas/generate-auth-url", methods=["GET"])
def build_auth_url():
auth_url = nylas.auth.url_for_oauth2(
config={
"client_id": os.environ.get("NYLAS_CLIENT_ID"),
"provider": 'imap',
"redirect_uri": REDIRECT_CLIENT_URI,
"login_hint": os.environ.get("AOL_IMAP_USERNAME"),
"state": "state",
}
)
return redirect(auth_url)
@flask_app.route("/oauth/exchange", methods=["GET"])
def exchange_code_for_token():
code_exchange_response = nylas.auth.exchange_code_for_token(
request={
"code": request.args.get('code'),
"client_id": os.environ.get("NYLAS_CLIENT_ID"),
"redirect_uri": REDIRECT_CLIENT_URI
}
)
return {
'email': code_exchange_response.email,
'grant_id': code_exchange_response.grant_id
}
# frozen_string_literal: true
require 'nylas'
require 'sinatra'
set :show_exceptions, :after_handler
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: "<NYLAS_API_KEY>")
get '/nylas/auth' do
config = {
client_id: "<NYLAS_CLIENT_ID>",
provider: 'imap',
redirect_uri: 'http://localhost:4567/oauth/exchange',
login_hint: '<AOL_IMAP_USER>',
state: "<state>"
}
url = nylas.auth.url_for_oauth2(config)
redirect url
end
get '/oauth/exchange' do
code = params[:code]
status 404 if code.nil?
begin
response = nylas.auth.exchange_code_for_token({
client_id: "<NYLAS_CLIENT_ID>",
redirect_uri: 'http://localhost:4567/oauth/exchange',
code: code
})
rescue StandardError
status 500
else
puts response
grant_id = response[:grant_id]
email = response[:email]
"Grant_Id: #{grant_id} \n Email: #{email}"
end
end
import java.util.*;
import static spark.Spark.*;
import com.nylas.NylasClient;
import com.nylas.models.*;
public class AuthRequest {
public static void main(String[] args) throws NylasSdkTimeoutError, NylasApiError {
NylasClient nylas = new NylasClient.Builder("<NYLAS_API_KEY>").build();
get("/nylas/auth", (request, response) -> {
List<String> scope = new ArrayList<>();
UrlForAuthenticationConfig config = new UrlForAuthenticationConfig(
"<NYLAS_CLIENT_ID>",
"http://localhost:4567/oauth/exchange",
AccessType.ONLINE,
AuthProvider.IMAP,
Prompt.DETECT,
scope,
true,
"sQ6vFQN",
"example@aol.com");
String url = nylas.auth().urlForOAuth2(config);
response.redirect(url);
return null;
});
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,
"<NYLAS_CLIENT_ID>",
"nylas");
try {
CodeExchangeResponse codeResponse = nylas.auth().exchangeCodeForToken(codeRequest);
return "%s".formatted(codeResponse);
} catch(Exception e) {
return "%s".formatted(e);
}
});
}
}
import com.nylas.NylasClient
import com.nylas.models.AccessType
import com.nylas.models.AuthProvider
import com.nylas.models.Prompt
import com.nylas.models.UrlForAuthenticationConfig
import spark.kotlin.Http
import spark.kotlin.ignite
fun main(args: Array<String>) {
val nylas: NylasClient = NylasClient(apiKey = "<NYLAS_API_KEY>")
val http: Http = ignite()
http.get("/nylas/auth") {
val scope = listOf("https://www.googleapis.com/auth/userinfo.email")
val config : UrlForAuthenticationConfig = UrlForAuthenticationConfig(
"<NYLAS_CLIENT_ID>",
"http://localhost:4567/oauth/exchange",
AccessType.ONLINE,
AuthProvider.IMAP,
Prompt.DETECT,
scope,
true,
"sQ6vFQN",
"<email_to_connect>")
val url = nylas.auth().urlForOAuth2(config)
response.redirect(url)
}
}
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,
"<NYLAS_CLIENT_ID>",
"nylas"
)
try {
val codeResponse : CodeExchangeResponse =
nylas.auth().exchangeCodeForToken(codeRequest)
codeResponse
} catch (e : Exception) {
e
}
}
Custom authentication
You can create grants with Custom authentication (POST /v3/connect/custom
) if you already have a password or app password for the end user.
The example below shows how to make a Custom authentication request with the correct provider and settings. The rest of the authentication process follows the same process as for non-IMAP grant creation.
curl -X POST https://api.us.nylas.com/v3/connect/custom \
--header 'Authorization: Bearer <NYLAS_API_KEY>' \
--header 'Content-Type: application/json' \
--data-raw '{
"provider": "imap",
"settings": {
"imap_username": "<IMAP_USERNAME>",
"imap_password": "<IMAP_PASSWORD>",
"imap_host": "imap.mail.me.com",
"imap_port": 993,
"smtp_host": "smtp.mail.me.com",
"smtp_port": 465
}
}'
For more information, see the Custom auth documentation.
Static IP support for IMAP accounts
Some email servers in secure environments only accept connections and data from a known list of sender IP addresses. If you need to connect to a server with these settings, you can add static IP support to your Nylas plan.
When you add static IP support to your plan, Nylas uses only a specific set of static IPs when connecting your application's users. You can then provide the administrators of those email servers with an allowlist of Nylas IPs so the user can authenticate with that server.
Static IP support is currently available for IMAP. Support for Exchange on-premises servers is coming soon.
To add static IP support to your Nylas account, contact your account representative or Nylas support.
Error handling for IMAP Hosted authentication
Nylas creates a grant only if both the IMAP settings are validated and the provider accepts the end user's login credentials. When an error occurs, the redirect_uri
includes an error_type
query parameter when the auth process is complete. The possible error_type
values are...
provider_not_responding
: The IMAP provider didn't respond to the login request from Nylas.invalid_authentication
: The provider responded with an incorrect credential error. Nylas prompts the user with an error message.auth_limit_reached
: The user entered an incorrect password three times. Nylas redirects back to your application'sredirect_uri
with the error code instead of showing an error message.
What's next?
Now that you have an IMAP connector and a grant, you can...
- Manage your connectors (previously called "integrations").
- Manage your grants.
- Review Nylas' event codes.