使用Firebase云功能实施发送电子邮件

时间:2017-06-29 19:22:05

标签: firebase google-cloud-functions

对于我们的网络应用,我们目前正在使用Firebase的免费计划,并且需要发送有关各种事件/触发器的电子邮件。问题是,我认为Mailgun可以完美地完成这项任务以及他们的云功能,但看起来可以将他们的API仅用于Firebase的付费计划,我们并不打算这样做我们的应用程序仍处于开发阶段时立即使用。因此,我们在没有了解如何使用Firebase以最少的金额实现电子邮件功能的情况下陷入困境(当我们对我们的应用程序是否会获得任何利润有点明确时,我们总是可以支付或支付更多费用)...任何人都可以帮助我。现在以任何方式(几乎)自由地进行 - 我们可以在以后随时升级吗?

谢谢! Piyush Soni

2 个答案:

答案 0 :(得分:18)

我在个人投资组合网站中使用firebase托管和云功能。我创建了一个云功能(http事件)来发送联系表单部分的电子邮件,我还没有启用结算选项,但免费报价(云功能执行)仍然足以满足我当前的需求。我通过以下方式发送电子邮件:

云功能:

const functions = require('firebase-functions');
const nodemailer = require('nodemailer');
const rp = require('request-promise');

//google account credentials used to send email
const mailTransport = nodemailer.createTransport(
    `smtps://user@domain.com:password@smtp.gmail.com`);

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

  //recaptcha validation
  rp({
        uri: 'https://recaptcha.google.com/recaptcha/api/siteverify',
        method: 'POST',
        formData: {
            secret: 'your_secret_key',
            response: req.body['g-recaptcha-response']
        },
        json: true
    }).then(result => {
        if (result.success) {
            sendEmail('recipient@gmail.com', req.body).then(()=> { 
              res.status(200).send(true);
            });
        }
        else {
            res.status(500).send("Recaptcha failed.")
        }
    }).catch(reason => {
        res.status(500).send("Recaptcha req failed.")
    })

});

// Send email function
function sendEmail(email, body) {
  const mailOptions = {
    from: `<noreply@domain.com>`,
    to: email
  };
  // hmtl message constructions
  mailOptions.subject = 'contact form message';
  mailOptions.html = `<p><b>Name: </b>${body.rsName}</p>
                      <p><b>Email: </b>${body.rsEmail}</p>
                      <p><b>Subject: </b>${body.rsSubject}</p>
                      <p><b>Message: </b>${body.rsMessage}</p>`;
  return mailTransport.sendMail(mailOptions);
}

更新,包括联系表单和脚本:

<form class="rsForm" action="/sendEmailCF" method="post">
    <div class="input-field">
        <label>Name</label>
        <input type="text" name="rsName" value="">
        <span class="line"></span>
    </div>

    <div class="input-field">
        <label>Email</label>
        <input type="email" name="rsEmail" value="">
        <span class="line"></span>
    </div>

    <div class="input-field">
        <label>Subject</label>
        <input type="text" name="rsSubject" value="">
        <span class="line"></span>
    </div>

    <div class="input-field">
        <label>Message</label>
        <textarea rows="4" name="rsMessage"></textarea>
        <span class="line"></span>
    </div>

    <input type="hidden" name="rsLang" value="en" />

    <span class="btn-outer btn-primary-outer ripple">
        <input class="formSubmitBtn btn btn-lg btn-primary" type="submit" data-recaptcha="global" value="Send">
    </span>
    <div id="recaptcha-global"></div>
</form>

处理表单提交的脚本:

$('.formSubmitBtn').on('click', function (e) {
    glForm = $(this).closest('.rsForm');
    var recaptchaId = 'recaptcha-' + $(this).data('recaptcha');
    var rsFormErrors = false;
    glFormAction = glForm.attr('action');
    var rsFormFields = glForm.find('.input-field');
    var rsFormName = glForm.find("[name='rsName']");
    var rsFormEmail = glForm.find("[name='rsEmail']");
    var rsFormMessage = glForm.find("[name='rsMessage']");

    // Button ripple effect
    ripple($(this).parent(), e.pageX, e.pageY);

    // Reset form errors
    rsFormFields.removeClass('error');
    rsFormErrors = false;

    // Validate form fields
    if(!rsFormName.val()) {
        rsFormErrors = true;
        rsFormName.parent().addClass('error');
    }

    if(!rsFormEmail.val() || !isValidEmail(rsFormEmail.val())) {
        rsFormErrors = true;
        rsFormEmail.parent().addClass('error');
    }

    if(!rsFormMessage.val()) {
        rsFormErrors = true;
        rsFormMessage.parent().addClass('error');
    }

    if(rsFormErrors) {
        // if has errors - do nothing
        return false;
    } else {

        if(rca[recaptchaId] === undefined){
            rca[recaptchaId] = grecaptcha.render(recaptchaId, {
                'sitekey' : 'sitekey',
                'callback' : onExecutedCaptcha,
                'size' : 'invisible',
                'badge':'inline'
            });

        } else {
            grecaptcha.reset(rca[recaptchaId]);
        }

        grecaptcha.execute(rca[recaptchaId]);
        return false;
    }
});

处理recaptcha响应和表单帖子的脚本:

function onExecutedCaptcha(token) {

  var sendingMsg = null, textMsg = null, textErr = null;
  var lang = glForm.find("[name='rsLang']").val();

  if(lang == 'es') {
      sendingMsg = 'Enviando mensaje...';
      textMsg = 'Tu mensaje se ha enviado con \u00e9xito!';
      textErr = 'Algo ha salido mal. Intenta mas tarde';
  } else {
      textMsg = 'Your email was sent successfully!';
      textErr = 'Oops! Something went wrong. Please try again.';
      sendingMsg = 'Sending email...';
  }

  swal({
    text: sendingMsg,
    button: false,
    closeOnClickOutside: false,
    closeOnEsc: false,
  });

    $.post( glFormAction,
        glForm.serialize(),
        function (response) {
            grecaptcha.reset();
            var data = jQuery.parseJSON( response );
            swal.close();

            if(data){
                swal({
                  text: textMsg,
                  icon: "success",
                });
                 glForm.find("input[type=text], input[type=email], textarea").val("");
            } else {
                swal({
                  text: textErr,
                  icon: "error",
                });
            }
        }
    );
}

答案 1 :(得分:3)

如果您升级到Blaze计划,则只需为您使用的内容付费,而对于云功能,您将获得免费的执行层数。

我不知道您的应用程序的具体细节,但是在大多数应用程序的开发过程中,您不太可能每月收取超过几美元的费用(可能只有几美分)。