Francisco X.
Francisco X.

Reputation: 11

FirebaseFunctions Cors No 'Access-Control-Allow-Origin'

I followed this tutorial but i use nodemailer instead of sendgrid.
https://www.youtube.com/watch?v=wCtNjP9gcqk

Im getting this error

Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'localhost:4200' is therefore not allowed access. The response had HTTP status code 500

I´ve tried several solution on the internet..

The most logic i found was this one...
https://mhaligowski.github.io/blog/2017/03/10/cors-in-cloud-functions.html

But i keep getting the error

This is what i have on the server side / firebase functions..

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


function sendFn(req, res) {
  var transporter = nodemailer.createTransport({
    service: "Gmail",
    auth: {
      user: "user@gmail.com",
      pass: "password"
    }
  });

  var mailOptions = {
    from: '', // sender address (who sends)
    to: '', // list of receivers (who receives)
    subject: '', // Subject line
    replyTo: '',
    text: '', // plaintext body
    html: '' // html body
  };

  mailOptions['from'] = 'Contact';
  mailOptions['to'] = 'address@email.com';
  mailOptions['text'] = req.query.msg;
  mailOptions['replyTo'] = req.query.email;;
  mailOptions['subject'] = "WebContact - " + req.query.name;

  // // send mail with defined transport object   

  return transporter.sendMail(mailOptions).then(() => {
    console.log('Email sent to:');
  }).catch(error => {
    console.error('There was an error while sending the email:', error);
  });
};


exports.httpEmail = functions.https.onRequest((req, res) => {
  var corsFn = cors();
  corsFn(req, res, function() {
    sendFn(req, res);
  });
});

This is what i've got on the front ... im using angular...

    const url = `firebase.url.function`;
    const params: URLSearchParams = new URLSearchParams();
    const headers = new Headers({ 'Content-Type': 'application/json'. , 'Access-Control-Allow-Origin': '*'});
    const options = new RequestOptions({ headers: headers });

    params.set('name', data['name']);
    params.set('email', data['email']);
    params.set('msg', data['msg']);

    console.log('Enviados' + params);

    this.http.post(url, params, options)
      .toPromise()
      .then(res => {
        console.log(res);
      })
      .catch(err => {
        console.log(err);
      });

Im lost how to change or set the cors on the firebase side ...

Thanks a lot

----EDIT----

Firebase Log.

TypeError: Cannot read property 'headers' of undefined
at /user_code/node_modules/cors/lib/index.js:219:31
at optionsCallback (/user_code/node_modules/cors/lib/index.js:199:9)
at corsMiddleware (/user_code/node_modules/cors/lib/index.js:204:7)
at exports.httpEmail.functions.https.onRequest (/user_code/index.js:54:18)
at cloudFunction (/user_code/node_modules/firebase-functions/lib/providers/https.js:26:41)
at /var/tmp/worker/worker.js:635:7
at /var/tmp/worker/worker.js:619:9
at _combinedTickCallback (internal/process/next_tick.js:73:7)
at process._tickDomainCallback (internal/process/next_tick.js:128:9)

Upvotes: 1

Views: 3164

Answers (1)

Georgi Arnaudov
Georgi Arnaudov

Reputation: 427

I had the same issue but used React for the front-end part. I managed to fix the issue by doing these steps:

Set these cors options when importing it



        const cors = require('cors');
        const corsOptions = {
                origin: '*',
                allowedHeaders: ['Content-Type', 'Authorization', 'Content-Length', 'X-Requested-With', 'Accept'],
                methods: ['GET', 'PUT', 'POST', 'DELETE', 'OPTIONS'],
                optionsSuccessStatus: 200 // some legacy browsers (IE11, various SmartTVs) choke on 204 
        };

    

When you try to send mail with nodemailer and use your Google credentials(email, password) Google will block the request because it is suspicious. So in order to send the mail using your Gmail account, you have to do the following:

  • Go to https://console.developers.google.com
  • Create new project if you haven't already
  • Then click on the blue button Create credentials...
  • Create OAuth Client ID
  • When it is ready click on it and the settings will open
  • You need to copy the client id and client secret. We will need them later
  • In the Authorized redirect URIs section add: https://developers.google.com/oauthplayground and https://developers.google.com/oauthplayground/ You can add only the one without the trailing slash, but I added them both because had some issues using only the one without the slash at the end.

  • Click save(make sure settings are saved, you will be redirected)

Now go to https://developers.google.com/oauthplayground/

Click on the settings button (the little cog) on the right and make sure you fill in your client id and secret there like shown on the screen. Auth playground step 1

After you are finished with this go to the Select and Authorize APIs and find the Gmail API and authorize it. enter image description here

If everything is okay you will be redirected to log in with your Google account. Login, then allow access to your app and you will be redirected again to the OAuth playground and check out Exchange authorization code for tokens tab: enter image description here

Copy the refresh token!

Then configure your Nodemailer transport settings like so:

const mailTransport = nodemailer.createTransport({
    service: 'Gmail',
    auth: {
        type: 'OAuth2',
        user: 'xxxxxx@gmail.com', // the email you signed on the auth playground
        clientId: 'cliend id here',
        clientSecret: 'client secret here',
        refreshToken: 'refresh token here'
    }
});

And here is my working Cloud Function:

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

    const corsMiddleware = cors(corsOptions);
    corsMiddleware(req, res, () => {
        mailTransport.sendMail({
            from: `blabla@gmail.com`, // sender address
            to: 'blah@gmail.com', // list of receivers
            subject: `You have got a new email!`, // Subject line
            html: `<div>Email body here</div>`
        }).then((info) => {
            res.status(200).send({ message: "Email sent"})
        }).catch(error => {
            res.send(error)
        });
    });

});

This is working for me, I hope works for you and the other ones who struggle! Good luck!

Upvotes: 1

Related Questions