What is Domain Warm-Up
Section titled “What is Domain Warm-Up”Nylas allows you to use your own custom email domain as well as a free nylas.email domain to send transactional emails. If you’ve already tried sending a few emails with your new domain and noticed they have been going to spam, the reason for this is because you have not established a strong sender reputation with providers like Gmail and Microsoft. This is where warming up your email domain comes into play.
Email domain warm-up is the gradual process of building trust for a new or inactive sending domain by steadily increasing both email sending volume and recipient engagement over time. This includes growing not only the number of emails sent, but also positive interactions such as opens, clicks, and replies.
By ramping up activity in a controlled and intentional way, domain warm-up helps establish a strong sender reputation with email service providers and improves long-term deliverability.
Why is Domain Warming Important?
Section titled “Why is Domain Warming Important?”Mailbox providers use sophisticated algorithms to fight spam and phishing. When they see a new sending domain suddenly blasting hundreds or thousands of emails, they get suspicious. Without an established reputation, your emails are more likely to be filtered out or rejected.
Warming your domain helps:
- Build sender reputation steadily
- Improve inbox placement rates
- Avoid blocks, throttling, or spam folder placement
- Protect your brand and IP from blacklists
How to Warm Your Domain: Step-by-Step
Section titled “How to Warm Your Domain: Step-by-Step”- Start Small and Slow
Begin sending very low volumes per day and gradually increase over weeks. Sudden spikes signal spammy behavior. Here is an example of a schedule to follow over 4 weeks assuming a daily target of 500-1000 emails during a typical 8-hour send window. Within each week, it is best to gradually increase the number every day or so by 10-20%.
| Week | Total Emails per Day | Emails per Hour (Approx.) | Notes |
|---|---|---|---|
| Week 1 | 5 - 15 | 1 - 2 | Start very low, focus on highly engaged recipients |
| Week 2 | 30 - 75 | 4 - 10 | Gradually increase volume, maintain steady increase |
| Week 3 | 150 - 300 | 20 - 40 | Moderate volume |
| Week 4 | 500 - 1,000+ | 60 - 125+ | Full ramp-up to target volume |
- Spread Sends Throughout the Day
Avoid sending all your emails at once. Spread sends evenly across business hours (e.g. 9AM - 5PM) with random delays between each message. The goal is to mimic natural sending patterns while establishing consistency.
- Use Real, Engaged Recipients
Send only to contacts who expect your emails and are likely to open, click, or reply. High engagement improves your reputation quickly. The table below summarizes different engagment types and the impact it has to your domain reputation. During your warm up period, let your email recipients know they should click links and reply to emails as this is the biggest positive signal that your content is not spam.
| Engagement Type | Description | Signal to Mailbox Providers |
|---|---|---|
| Open | Recipient opens the email | Positive: indicates interest and legitimacy |
| Click | Recipient clicks on links inside the email | Strong positive: signals active engagement |
| Reply | Recipient replies to the email | Very strong positive: shows two-way interaction |
| Mark as Spam | Recipient marks email as spam | Strong negative: harms sender reputation |
| Delete Without Reading | Recipient deletes email without opening | Negative: signals low relevance or trust |
| Move to Inbox/Folder | Recipient moves email from spam to inbox | Positive: improves sender reputation |
| Forward | Recipient forwards email to others | Positive: extends reach and trust |
| Bounce (Hard/Soft) | Email fails to deliver (invalid address, etc.) | Negative: especially hard bounces harm reputation |
- Content Matters
Transactional emails (like password resets, order confirmations) have higher trust and open rates than marketing blasts. Avoid spammy or promotional content during warm-up. No all-caps, excessive links, or aggressive sales language early on. Introduce slight variations to the email content while maintaining consistent branding.
Example Script
Section titled “Example Script”You can use the following python script to start warming up your new email domain. The script is meant to be run daily and takes care of sending a specified number of emails throughout a given time window using the Nylas Transactional Send API. It does NOT automate engagment of these emails which is equally important in the warm-up process so make sure you choose recipients who will engage. You can use a cron job that is set up to run it at the start of your business day (e.g. 9AM). At the end of every week, you should update the script’s total daily target to match the schedule you are following.
You will need to replace the appropriate lines of code with your:
- Email domain
- API key
- Recipients list: Use real people who will engage with your emails. High engagement is key to a good domain reputation. Make sure to use a variety of email providers.
- Daily email target: Use the schedule suggested above. You should update the script every few days or at the end of every week with the new daily target.
- Send window: The length of time during which sends can happen. We recommend using the time period you expect emails to be sent at. For most scenarios, this is during business hours so your send window should be 8-10 hours.
- Email content: We recommend using content that mimics what you will be actually sending. This might be booking confirmation, password resets, etc. See the Transaction Send API docs for more information on what you can include in the request.
import requestsimport jsonimport timeimport randomimport math
# ============ VARIABLES TO UPDATE ============# Update all the variables in this section. Also update the payload which is outside of# this section, further down in the script.
base_url = "https://api.us.nylas.com"email_domain = "your-subdomain.nylas.email"api_key = "your-api-key"
# List of recipients to send emails to. Use recipients that you know will engage with the# email. You should include a mix of different email providers.recipients = []
send_window = 8 # In hours. Use 8-10 hour window to mimic business hours.total_emails_to_send = 10 # Your daily send target.
# ============================================
url = f'{base_url}/v3/domains/{email_domain}/messages/send'headers = { "Authorization": f"Bearer {api_key}", 'Content-Type': 'application/json',}emails_per_hour = math.ceil(total_emails_to_send / send_window)
print(f"Script started! Sending {total_emails_to_send} emails over {send_window} hours")
for hour in range(1, send_window + 1): print(f"Sending emails for hour {hour} of {send_window}") start_time = time.time()
if len(recipients) < emails_per_hour: # Allow for duplicates if there are less recipients than emails to send. random_recipients = random.choices(recipients, k=emails_per_hour) else: random_recipients = random.sample(recipients, emails_per_hour)
for recipient in random_recipients: # Update this payload with your own email content and "from" information. # See Transactional Send API docs for more info. payload = { "to": [recipient], "from": { "name": "ACME Corporation", }, "template": { "id": "your-template-id", "variables": { "name": recipient["name"], "email": recipient["email"], "booking": { "start_time": 1768856240, "end_time": 1768856240, "location": "123 Main St", } } } }
response = requests.post(url, headers=headers, data=json.dumps(payload))
if response.ok: print(f"Successfully sent email to {recipient['email']}") else: print(f"Could not send email to {recipient['email']}") print(response.text)
# Randomly send the emails throughout the hour. We will wait at least 1 minute between each send # but the wait time will be longer if there are less emails to send in that hour. max_wait_time_minutes = max(1, math.ceil(60 / emails_per_hour)) jitter_seconds = random.uniform(0, 10) random_delay_seconds = random.uniform(60, max_wait_time_minutes * 60) + jitter_seconds print(f"Waiting {random_delay_seconds / 60} minutes before sending next email") time.sleep(random_delay_seconds)
# Once all emails are sent for the hour, we wait until the next hour to start sending again. time_till_next_hour = 3600 - (time.time() - start_time)
if time_till_next_hour > 0: print(f"Waiting {time_till_next_hour / 60} minutes until next hour") time.sleep(time_till_next_hour)