Abstract
This article describes how to send emails in Wix Code using Gmail, Outlook, Yahoo, Mailgun and many more by using emailJS.com´s REST API.
Thanks
to Sasha from emailJS.com, who was incredibly helpful. If you use this code and their service, drop him a line through the chat window. Mention Wix Code and Girizano, then he´ll know.
PS: I do not get any kickbacks from them, I am not affiliated with them, nor do I have any other financial interests in their company or products.
The problem
At the moment of writing, Wix Code only had some example code for sending emails with SendGrid. Many commented in the forum that the free version had some problems (like emails not arriving because they came from a blacklisted IP-address).
The cheapest paid version is about USD 10 a month. My client sends maybe 100 emails per year at best. That would work out at over 1 USD per email, something I could not sell.
So I started looking out for sending emails cheaper.
The solution
On the Wix Code forum I found this post by Luigi. In the Stackoverflow link I saw a comment about "emailjs.com", something I had never heard of. I checked it out, started chatting with Sasha and within 10 minutes he posted a piece of example code on PasteBin. I took it from there.
What is emailJS.com?
They describe their service as a proxy-server onto email providers. In plain French that means that they offer a unified interface onto many, many email providers: you write your code once, and you only change the email provider if you want to use another one: the rest of your code stays the same.
They work with templates (to be edited on their site) holding variables within double curly brackets, like {{to_email}}. The free account gives you 200 emails per month, a footer holding "Email sent using emailJS.com", but no attachments.
They offer two interfaces, HTML and REST. We used the latter.
Pricing
At the time of writing, emailJS.com gives you 200 emails a month for free. The next level up is a 1000 emails per month for USD 5 a months (monthly payment) or USD 4 (yesrly payment), a substantial saving compared to SendGrid. And if you attach a gmail account, sending emails is free. A provider like Mailgun gives you 10000 free emails, so there are no extra costs involved in my scenario.
Setting up your account
It´s all pretty straight forward. You must setup a template using the right variables, so I include a screen shot from my settings for the example (a simple inquiry holding Name, Arrival Date, Departure Date and Remarks).
IMPORTANT
look at the below screen shot and make sure you get all the correct vars in the correct fields!!!
the template name here is "inquiry_form". If you use another name, please change code accordingly;
we assume that the Gmail Email Service you defined in emailjs is called "gmail". If not, change code accordingly.
The user_id
In all of their examples, the user_id is sent within the code, thus plainly visible, so this can be abused. Sasha explained that, because you use templates, a hacker would not be very interested. But, you can use one variable (like {{body}} which holds all the (formatted) body content, so that could be misused. To avoid this, we put the user_id in the backend code.
I think this is OK, but any comments are welcome.
The code
1) Put this in a backend file called email.jsw
//email.jsw
import {fetch} from 'wix-fetch';
export function sendEmail(emailprovider, template, params) {
const userid = "user_xxxxxxxxxxxxxxxxxxxxxx"; // put your emailjs userid here (look in Account)
const url = "https://api.emailjs.com/api/v1.0/email/send";
// if no email provider specified, then use this one
if (!emailprovider) {
emailprovider="gmail";
}
// if no email template specified, then use this one
if (!template) {
template="inquiry_form";
}
let full_params = {
"user_id": userid,
"service_id": emailprovider,
"template_id": template,
"template_params": params
};
const headers = {
"Content-type": "application/json"
};
const request = {
method: 'POST',
headers: headers,
body: JSON.stringify(full_params)
};
return fetch(url, request)
.then((httpResponse) => {
if (httpResponse.ok) {
console.log('Your mail is sent!');
} else {
return httpResponse.text()
.then(text => Promise.reject(text));
}
})
.catch((error) => {
console.log('Oops... ' + error);
});
}
2) in Wix, make a page with 1 button (here called button2) and paste this code:
import {sendEmail} from 'backend/email';
$w.onReady(function () {
});
export function button2_click(event, $w) {
// sendEmail is called with: email provider name (like:gmail), template id (like "thanks_for_interest") and params.
// params holds ALL variables for your email: sender name/email, recipients, cc´s, bcc´s, subject, body and more specific
// values to fill the template, like, in our example, Arrival, Departure and Remarks.
let myprovider = "gmail"; //use her the alias you used for this service in emailJS
let mytemplate = "inquiry_form"; //use her the template name you defined in emailJS
let myparams = {
"from_email": "foo1@bar.com",
"to_email": "foo2@bar.com",
"replyto_email": "foo1@bar.com",
"cc_email": "foo3@bar.com",
"Arrival": "25-03-2018",
"Departure": "28-03-2018",
"Remarks": "Could we have coffee instead of tea for breakfast?",
"from_Name": "Giri´s Code Corner"
};
sendEmail (myprovider, mytemplate, myparams);
}
My results
Well, in short: flawless. I tested it with a gmail account and with mailgun and every email, cc, and bcc was received. Hope it works for you too.
And don´t forget to thank Sasha!!!!
Update 29-03-2018
Former version of code would generate a console error in browser like 'Uncaught (in promise) Error: invalid json response body at https://api.emailjs.com/api/v1.0/email/send reason: Unexpected token O in JSON at position 0'
This was caused by the (old) response.JSON. Now corrected it and put some more console.log´s in the fetch part plus error handling.
Also added replyto_email in params as an example (see below)
Update 29-03-2018
If you send thru mailgun (and other bulk providers), it lets you spoof the sender (so yes, you could send mails from billgates@microsoft.com). This comes in handy when, in our case, you want people to fill out a form with their email address and then send an email from that email address to others.
I noticed that gmail doesnot allow this and substitutes the "from_email" with the email account you are sending from. Workaround: use {{replyto_email}} as in example
Update 29-03-2018
Changed the code a bit, so now the params are filled in the front end (with the buttonclick) instead of at the backend. That worked, but this example is more like real world scenario
Update 14-09-2019
Tried to send 23 messages in bulk. Only 3 came thru (200 server response), the rest with error codes (some 400 code). Talked to the people from emailjs.com about it. This is the gist of it:
1) emailjs.com is not setup for bulk emailing. They need AT LEAST a 1 second pause between 1 email and the next
2)gmail also seems to have these limitations. Also, sending emails thru gmail on a personal account thru an API is limited to 100 per day
In short, if you want to use bulk email sending, do not use a gmail account, but something else (like mailgun). But you MUST have a 1 second delay AT LEAST between emails using emailjs.
What would prob. be best it to send email, wait for the response (200 or not). If not 200, use a progressive back-off: you wait a second, retry, if still fail, wait 2 secs, etc, then send second email.
Hello Girizano,
I have followed your tutorial exactly, and yet my emails will not send... so a quick question:
on the page code, following ' let myparams = { ' the values following each param id, do the require to be in quotations?
I am trying to assign the value of user input fields to the params as such:
import {sendEmail} from 'backend/email';
export function quickButton_click(event, $w) { let myprovider = "gmail"; let mytemplate = "quick_estimate";
let params = { "to_email":"xxxxxx@xxxxxxx.xxx", // email hidden for privacy "cc_email":"xxxxxx@xxxxxxx.xxx", // email hidden for privacy "from_name": $w("#repName").value, //reference to text input field "from_email": $w("#repEmail").value, //reference to text input field "replyto_email": $w("#repEmail").value, //reference to text input field
"Location": $w("#repLocation").value, //reference to dropdown menu
.....…