Blog Logo

Send Emails to Your Clients Almost FREE 📧 | SMTP Server with Oracle Cloud

Send Emails to Your Clients Almost FREE with Oracle Cloud


Surely it has happened to you sometime: you buy a domain out there, you set up your cool website and suddenly you think
 “What if I could send emails to my clients?”

It is super typical when you create a Software as a Service. You put that “Join the waiting list” box and then you want to send an email to all the people who have signed up. Normal, right?

To be able to send bulk emails you need an SMTP server, and the truth is that it is not always easy to get it. If you set it up yourself on your own server, the IP may not have a good reputation and your emails end up straight in spam. Apart from the fact that it is a hassle to do it.

There are already services that help us with this (SendGrid, Mailgun, Amazon SES, Resend
), but believe me when I tell you that they are expensive. Although it may not seem like it at first, they are. At least compared to what I’m going to show you today.

In this post I am going to show you:

  1. What on earth is an SMTP server (in case you are not clear yet)
  2. Why popular services bleed your pocket dry
  3. How to get an SMTP almost for free with Oracle Cloud
  4. Example code so you can see how easy it is to use it

Let’s get to it!


What is an SMTP server? (Explained easily)

SMTP stands for Simple Mail Transfer Protocol.

Think of it as a “digital postman” in charge of your email going from your server to the recipient’s inbox.

How does it work? Very easy:

  1. Connection: Your application connects to the SMTP server using a port (usually 25, 465 or 587)
  2. Identification: The server asks you “who are you?” and checks that you have permission to send
  3. Delivery: Your app tells the server “hey, send this message to client@example.com” and passes the content
  4. Distribution: The server queries the MX records of the destination domain, finds the corresponding “postman” and sends the email

smtp-workflow.webp

Basically, SMTP is like the central post office: your server puts the letter in the mailbox, and from there the SMTP protocol distributes it until it reaches the recipient.

Simple, right? Without this you cannot send emails from your application. As simple as that.


Let’s see what the best-known services offer us and why they are going to cost you an arm and a leg.

SendGrid

sendgrid-pricing.webp

SendGrid is one of the best known, but its prices scale fast:

  • Free: 100 emails/day
  • Essentials ($19.95/month): 50,000 emails
  • Pro ($89.95/month): 100,000 emails

Mailgun

Similar story with Mailgun:

  • Free: 5,000 emails for 3 months, then paid
  • Foundation ($35/month): 50,000 emails
  • Growth ($80/month): 100,000 emails

Resend (the current favorite)

resend-pricing.webp

Resend is becoming very popular lately because it has a very accessible panel where you can see statistics of emails sent, recipients, and it also has a simple SDK to apply it in your projects.

Its free tier allows 3,000 free emails per month, which is quite good. But when you want to go further:

  • Pro ($20/month): 50,000 emails (limited to 10 domains)
  • Business ($90/month): 100,000 emails

If your current goal is only to send 3,000 emails or less per month from one email address, Resend is enough for you. You can stop reading and go to resend.com right now.

But if you plan to have much more traffic or manage sending from different email addresses



The alternative no one tells you about: Oracle Cloud SMTP

Here is where the hidden gem comes in. Oracle Cloud offers an SMTP service that is ridiculously cheap.

If you are already a follower of the blog, you will know that thanks to Oracle we have managed to have a server with 24GB of RAM and 4 cores totally free. Here is the complete tutorial.

Well Oracle Cloud offers many more things apart from VPS, and one of them is its SMTP service.

oracle-smtp-pricing.webp

The prices you will fall in love with

Hold on tight because the price is GREAT:

  • 3,000 free emails (matches Resend)
  • After: $0.085 for every 1,000 emails (8 cents, about 7 euro cents)

Real price comparison

Let’s do the calculations that no one does:

Emails/monthResendOracle CloudSavings
50,000$20~$4.0080% less
100,000$90~$8.2591% less
200,000$180~$16.7591% less

Calculation for 50,000 emails:

  • 50,000 - 3,000 (free) = 47,000 paid emails
  • 47 × $0.085 = $3.995 ≈ $4.00

Calculation for 100,000 emails:

  • 100,000 - 3,000 (free) = 97,000 paid emails
  • 97 × $0.085 = $8.245 ≈ $8.25

It’s laughable how prices are reduced. And all this without counting the additional advantages:

Advantages that Resend does not give you

  1. No domain limit: Resend restricts you to 10 domains on the $20 plan. Oracle has no restrictions
  2. Pay per real use: If one month you only send 20,000 emails, you only pay ~$1.45. In Resend you pay the entire fee
  3. Scalability: You can grow without brutal price jumps

The only “disadvantage” is that you don’t have that nice Resend SDK, but later I will show you how simple it is to use a normal SMTP.


How to get your SMTP server in Oracle Cloud

Step 1: Create an account in Oracle Cloud

The first thing is to create an account in Oracle Cloud if you don’t have it yet. Important tip: put real data, since at the end of the registration they will ask for card verification to confirm that the name matches yours.

Once the account is created, if you only want to use the free layer you won’t have to do anything else. Note: the free layer allows you to send only 100 emails a day (same as Resend).

If you want to continue without daily restrictions:

  1. Click “Upgrade” in the message that appears above
  2. If it does not appear, search for “Billing” in the menu
  3. Click “Upgrade account” in the “Pay as you go” section
  4. In a matter of minutes or hours you will receive confirmation by email

Step 3: Configure the Email Delivery service

While we wait for confirmation, we can configure:

  1. Search for “Email Delivery” in the Oracle Cloud menu
  2. Create a new email configuration
  3. Add your domain and configure it with Cloudflare or your DNS provider
  4. Verify the domain following the instructions (add DNS/SPF/DKIM records)

oracle-email-config.webp

Step 4: Get SMTP credentials

Once the domain is verified, in “Configuration” all the information to connect to the SMTP will appear. Save this info:

  • Host: smtp.email.region.oci.oraclecloud.com
  • Port: 587 (TLS) or 25

Step 5: Generate user credentials

Important: SMTP credentials do NOT match your portal access password. They are generated and shown only once, so don’t lose them.

To get your SMTP password:

  1. Go to Identity → Domains → Default domain → Users
  2. Find your user and enter SMTP credentials
  3. Click Generate credentials
  4. Save the user and password that appear

The user will be a very long text string, but it is normal.

oracle-smtp-credentials.webp

You have everything! Host, port, user, password and source email. Any external service you use and asks for SMTP information you can provide it.


Example code: How to use your SMTP in a real application

“Hey Edu, I’m a programmer and I loved Resend because it was as easy as calling their API, what do I do now with so many things?”

Relax, if you are a programmer you will know that nothing is impossible. And doing this is super easy.

I have prepared an example project in Astro (but you can adapt it to Next.js, React, Node.js, Java
 whatever you want).

Installation of dependencies

npm install nodemailer
npm install --save-dev @types/nodemailer

Environment variables

Create your .env file with Oracle credentials:

SMTP_HOST=smtp.email.eu-frankfurt-1.oci.oraclecloud.com
SMTP_PORT=587
SMTP_USER=your_super_long_oracle_user
SMTP_PASS=your_generated_password
SMTP_FROM=noreply@yourdomain.com

Endpoint code

// src/pages/api/send-email.ts
import type { APIRoute } from 'astro';
import nodemailer from 'nodemailer';
import fs from 'fs';
import path from 'path';

interface EmailRequest {
  to: string;
  type: 'raw' | 'template';
  message?: string;
  templateData?: {
    name: string;
    [key: string]: any;
  };
}

export const POST: APIRoute = async ({ request }) => {
  try {
    // Read and validate the body
    const body: EmailRequest = await request.json();
    
    // Basic validations
    if (!body.type || !['raw', 'template'].includes(body.type)) {
      return new Response(
        JSON.stringify({ error: 'Invalid email type' }),
        { status: 400, headers: { 'Content-Type': 'application/json' } }
      );
    }

    if (!body.to || body.to.trim() === '') {
      return new Response(
        JSON.stringify({ error: 'Destination email required' }),
        { status: 400, headers: { 'Content-Type': 'application/json' } }
      );
    }

    // Read environment variables
    const smtpHost = import.meta.env.SMTP_HOST;
    const smtpPort = parseInt(import.meta.env.SMTP_PORT);
    const smtpUser = import.meta.env.SMTP_USER;
    const smtpPass = import.meta.env.SMTP_PASS;
    const smtpFrom = import.meta.env.SMTP_FROM;

    if (!smtpHost || !smtpPort || !smtpUser || !smtpPass || !smtpFrom) {
      return new Response(
        JSON.stringify({ error: 'Incomplete SMTP configuration' }),
        { status: 500, headers: { 'Content-Type': 'application/json' } }
      );
    }

    // Create nodemailer transporter
    const transporter = nodemailer.createTransporter({
      host: smtpHost,
      port: smtpPort,
      secure: false, // true for port 465, false for others
      auth: {
        user: smtpUser,
        pass: smtpPass,
      },
    });

    // Prepare email content
    let subject: string;
    let htmlContent: string;

    if (body.type === 'raw') {
      if (!body.message || body.message.trim() === '') {
        return new Response(
          JSON.stringify({ error: 'Message required for raw email' }),
          { status: 400, headers: { 'Content-Type': 'application/json' } }
        );
      }
      
      subject = 'Message from your application';
      htmlContent = `<p>${body.message}</p>`;
      
    } else { // template
      subject = 'Welcome to our platform';
      
      // Read HTML template
      const templatePath = path.join(process.cwd(), 'src', 'templates', 'welcome.html');
      let template = fs.readFileSync(templatePath, 'utf-8');
      
      // Replace template variables
      if (body.templateData) {
        Object.keys(body.templateData).forEach(key => {
          template = template.replace(`{{${key}}}`, body.templateData![key]);
        });
      }
      
      htmlContent = template;
    }

    // Send the email
    const info = await transporter.sendMail({
      from: smtpFrom,
      to: body.to,
      subject: subject,
      html: htmlContent,
    });

    return new Response(
      JSON.stringify({ 
        success: true, 
        messageId: info.messageId,
        message: 'Email sent successfully' 
      }),
      { status: 200, headers: { 'Content-Type': 'application/json' } }
    );

  } catch (error) {
    console.error('Error sending email:', error);
    return new Response(
      JSON.stringify({ error: 'Internal server error' }),
      { status: 500, headers: { 'Content-Type': 'application/json' } }
    );
  }
};

Example HTML Template

Create src/templates/welcome.html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Welcome</title>
</head>
<body style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
    <div style="background: #f8f9fa; padding: 20px; text-align: center;">
        <h1 style="color: #333;">Hello {{name}}!</h1>
        <p style="color: #666; font-size: 16px;">
            Welcome to our platform. We are excited to have you with us.
        </p>
        <a href="https://yourdomain.com" 
           style="background: #007bff; color: white; padding: 12px 24px; 
                  text-decoration: none; border-radius: 5px; display: inline-block;">
            Start now
        </a>
    </div>
</body>
</html>

How to use the endpoint

// Simple email sending
const response = await fetch('/api/send-email', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    to: 'client@example.com',
    type: 'raw',
    message: 'Hello, this is a test message'
  })
});

// Sending with template
const response = await fetch('/api/send-email', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    to: 'client@example.com',
    type: 'template',
    templateData: {
      name: 'John Doe'
    }
  })
});

As you can see, sending emails with SMTP is very similar to Resend. The syntax barely changes, and you have much more control over the process.


Complete repository

I have uploaded all the example code to GitHub so you can download it and use it as a reference: View repository

VERY IMPORTANT! Do not forget to configure your .env file with the properties we have seen in Oracle, otherwise it will not be able to log in.


Conclusion: The SMTP you needed

As you can see, setting up a cheap and scalable email sending service is not complicated at all. Oracle Cloud offers you:

✅ 3,000 free emails to start ✅ Ridiculous prices later (91% cheaper than the competition) ✅ No domain limits ✅ Pay per real use ✅ Scalability without brutal price jumps

The only “downside” is that you don’t have an SDK as visual as Resend, but with the code I’ve shown you, you have everything you need.

If you want to take your automations a step further, I recommend you check out N8N, an automation tool that is revolutionizing the market. Here is the complete tutorial to install it for free.


See you in the next blog! ❀


What do you think?

Leave your opinion, question or suggestion. Comments are synced with GitHub Discussions .

← Back to blog