17

I'm aware that Firebase doesn't allow you to send emails using 3rd party email services. So the only way is to send through Gmail.

So I searched the internet for ways, so here's a snippet that works and allows me to send email without cost.

export const shareSpeechWithEmail = functions.firestore
  .document("/sharedSpeeches/{userId}")
  .onCreate(async (snapshot, context) => {
    // const userId = context.params.userId;
    // const data = snapshot.data();
    const mailTransport = nodemailer.createTransport(
      `smtps://${process.env.USER_EMAIL}:${process.env.USER_PASSWORD}@smtp.gmail.com`
    );


    const mailOptions = {
      to: "test@gmail.com",
      subject: `Message test`,
      html: `<p><b>test</b></p>`
    };
    try {
      return mailTransport.sendMail(mailOptions);
    } catch (err) {
      console.log(err);
      return Promise.reject(err);
    }
  });

I want to create a template, so I used this package called email-templates for nodemailer. But the function doesn't get executed in Firebase Console and it doesn't show an error and shows a warning related to "billing".

export const shareSpeechWithEmail = functions.firestore
  .document("/sharedSpeeches/{userId}")
  .onCreate(async (snapshot, context) => {

    const email = new Email({
      send: true,
      preview: false,
      views: {
        root: path.resolve(__dirname, "../../src/emails")
        // root: path.resolve(__dirname, "emails")
      },
      message: {
        // from: "<noreply@domain.com>"
        from: process.env.USER_EMAIL
      },
      transport: {
        secure: false,
        host: "smtp.gmail.com",
        port: 465,
        auth: {
          user: process.env.USER_EMAIL,
          pass: process.env.USER_PASSWORD
        }
      }
    });

    try {
      return email.send({
        template: "sharedSpeech",
        message: {
          to: "test@gmail.com",
          subject: "message test"
        },
        locals: {
          toUser: "testuser1",
          fromUser: "testuser2",
          title: "Speech 1",
          body: "<p>test using email <b>templates</b></p>"
        }
      });
    } catch (err) {
      console.log(err);
      return Promise.reject(err);
    }
  });
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
The.Wolfgang.Grimmer
  • 1,172
  • 2
  • 9
  • 32

5 Answers5

11

You can definitely send emails using third party services and Cloud Functions, as long as your project is on the Blaze plan. The official provided samples even suggest that "if switching to Sendgrid, Mailjet or Mailgun make sure you enable billing on your Firebase project as this is required to send requests to non-Google services."

https://github.com/firebase/functions-samples/tree/main/Node-1st-gen/quickstarts/email-users

The key here, no matter which email system you're using, is that you really need to upgrade to the Blaze plan in order to make outgoing connections.

IcyIcicle
  • 564
  • 3
  • 15
Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
  • Let's say i enabled blaze plan and send an email using sendgrid. Would it cost something even if i haven't reached a quota in their free plan? – The.Wolfgang.Grimmer Nov 19 '19 at 19:24
  • 1
    If you have billing question, please consult the [pricing guide](https://firebase.google.com/pricing/). If that doesn't have enough information, please reach out to Firebase support for billing questions. https://support.google.com/firebase/contact/support – Doug Stevenson Nov 19 '19 at 19:59
8

you can send emails by using nodemailer:

npm install nodemailer cors

const functions = require('firebase-functions');
const admin = require('firebase-admin');
const nodemailer = require('nodemailer');
const cors = require('cors')({origin: true});
admin.initializeApp();

/**
* Here we're using Gmail to send 
*/
let transporter = nodemailer.createTransport({
    service: 'gmail',
    auth: {
        user: 'yourgmailaccount@gmail.com',
        pass: 'yourgmailaccpassword'
    }
});

exports.sendMail = functions.https.onRequest((req, res) => {
    cors(req, res, () => {

        // getting dest email by query string
        const dest = req.query.dest;

        const mailOptions = {
            from: 'Your Account Name <yourgmailaccount@gmail.com>', // Something like: Jane Doe <janedoe@gmail.com>
            to: dest,
            subject: 'test', // email subject
            html: `<p style="font-size: 16px;">test it!!</p>
                <br />
            ` // email content in HTML
        };

        // returning result
        return transporter.sendMail(mailOptions, (erro, info) => {
            if(erro){
                return res.send(erro.toString());
            }
            return res.send('Sended');
        });
    });    
});

See also here

Set Security-Level to avoid error-messages: Go to : https://www.google.com/settings/security/lesssecureapps set the Access for less secure apps setting to Enable

Refer to

Micha
  • 906
  • 6
  • 9
5

Call a sendMail() cloud function directly via functions.https.onCall(..) :

As @Micha mentions don't forget to enable Less Secure Apps for the outgoing email: https://www.google.com/settings/security/lesssecureapps

const functions = require('firebase-functions');
const nodemailer = require('nodemailer');

let mailTransport = nodemailer.createTransport({
    service: 'gmail',
    auth: {
        user: 'supportabc@gmail.com',
        pass: '11112222'
    }
});

exports.sendMail = functions.https.onCall((data, context) => {

    console.log('enter exports.sendMail, data: ' + JSON.stringify(data));

    const recipientEmail = data['recipientEmail'];
    console.log('recipientEmail: ' + recipientEmail);

    const mailOptions = {
        from: 'Abc Support <Abc_Support@gmail.com>',
        to: recipientEmail,
        html:
           `<p style="font-size: 16px;">Thanks for signing up</p>
            <p style="font-size: 12px;">Stay tuned for more updates soon</p>
            <p style="font-size: 12px;">Best Regards,</p>
            <p style="font-size: 12px;">-Support Team</p>
          ` // email content in HTML
    };

    mailOptions.subject = 'Welcome to Abc';

    return mailTransport.sendMail(mailOptions).then(() => {
        console.log('email sent to:', recipientEmail);
        return new Promise(((resolve, reject) => {
       
            return resolve({
                result: 'email sent to: ' + recipientEmail
            });
        }));
    });
});

Thanks also to: Micha's post

Gene Bo
  • 11,284
  • 8
  • 90
  • 137
1

You can send for free with Firebase extensions and Sendgrid:

https://medium.com/firebase-developers/firebase-extension-trigger-email-5802800bb9ea

woshitom
  • 4,811
  • 8
  • 38
  • 62
0

DEPRECATED: https://www.google.com/settings/security/lesssecureapps

Use "Sign in with App Passwords": https://support.google.com/accounts/answer/185833?hl=en to create an app password.

follow the steps in the link then use the given password with your user in mailTransport:

const mailTransport = nodemailer.createTransport({
    service: 'gmail',
    auth: {
        user: 'user@gmail.com',
        pass: 'bunchofletterspassword'
    }
});
Jonathan L
  • 11
  • 3