OAuth2 Implicit vs Authorization Code Grant for Fitbit API - javascript

THE ANSWER TO THIS QUESTION WAS IN THE FACT THAT I WAS USING AUTHORIZATION CODE GRANT FLOW ON THE CLIENT SIDE.. THIS SEEMS TO RESULT IN BLOCKING ERROR..
CHECK UNDERNEATH FOR FUNCTIONING AUTHENTICATION OAUTH2 IMPLICIT GRANT FOR FITBIT API..
I am performing OAuth2 authentication against the Fitbit API. This all using the Authorization Code Grant Flow. So first getting the auth code, being redirected to my application, then exchanging this for the access token and getting data with this token.
Starting off at the homePage on the "post_request.html" page, pushing the "fitbit" button, the user is redirected to the Authorization EndPoint of Fitbit. I am using Node.js to build a localserver to host the application and to be able to redirect without any problem..
On being redirected, I retrieve the authorization code and make an AJAX POST request to trade the authorization code for an access token. I then make this POST request but I get the following error..
{"errors":[{"errorType":"invalid_client","message":"Invalid authorization header format. The header was not recognized to be a valid header for any of known implementations or a client_id was not specified in case of a public client Received header = BasicdW5kZWZpbmVk. Visit https://dev.fitbit.com/docs/oauth2 for more information on the Fitbit Web API authorization process."}],"success":false}
I think there might be an error in me url encoding the client_id and client_secret. Or in me setting the headers. But I cannot spot it. Can anyone help me out?
My HTML file is the following..
<body>
<button onclick="fitbitAuth()">Fitbit</button>
<!-- action = route, method = method -->
<form action="/" method="POST" id="form">
<h3>Email Address:</h3>
<input type="email">
<br>
<h3>Password:</h3>
<input type="password">
<br>
<br>
<button type="submit">Send Request</button>
</form>
</body>
</html>
My script is the following, it consists of 3 functions..
- base64 encoding function
- onclick function for starting the OAuth2 process
- function that trades in auth code for access token
// run this script upon landing back on the page with the authorization code
// specify and/ or calculate parameters
var url_terug = window.location.search;
var auth_code = url_terug.substr(6);
var granttype = "authorization_code";
var redirect_uri = "http://localhost:3000/fitbit";
var client_id = "xxxxx";
var client_secret = "xxxxxxxxxxxx";
var stringto_encode = client_id + ":" + client_secret;
var encoded_string = "";
console.log("auth code = " + auth_code);
function baseEncode(stringto_encode){
encoded_string = btoa(stringto_encode);
console.log(encoded_string);
}
function getTokenFitBit(){
baseEncode();
// execute a POST request with the right parameters
var request = new XMLHttpRequest();
request.open('POST', "https://api.fitbit.com/oauth2/token?client_id=" + client_id + "&grant_type=" + granttype + "&redirect_uri=" + redirect_uri + "&code=" + auth_code);
request.setRequestHeader('Authorization', 'Basic'+ encoded_string);
request.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
// Setup our listener to process completed requests
request.onload = function () {
// Process our return data
// status code between 200 and 300 indicates success
if (request.status >= 200 && request.status < 300) {
console.log('success!', request);
console.log(request.responseText);
// continue with API calls..
// you could set up a broader response handling if there is a use case for it
} else {
console.log('The current token request failed!');
}
};
request.send();
}
getTokenFitBit();
// get the access token out of the JSON response
// execute a GET request on the API endpoint
// handle the data
// upon clicking fitbit button, starting off the oauth2 authentication
function fitbitAuth() {
window.location.href = 'https://www.fitbit.com/oauth2/authorize?client_id=xxxxx&response_type=code&scope=activity&redirect_uri=http://localhost:3000/fitbit&prompt=consent';
}

In the above example, you appear to have missing a separator between the "Basic" header and it's value in this line:
request.setRequestHeader('Authorization', 'Basic'+ encoded_string);
Provided you are building a web based applications, you may want to look into using the 'Implicit' Flow, too: https://oauth.net/2/grant-types/implicit/

The following code functions and uses the implicit grant flow. It works with FitBit API, Node.js to redirect to the application, and then client-side authentication.
Code for the Node.js local server module
// PROJECT authenticating Fitbit OAuth2 Implicit Grant
const express = require("express");
const app = express();
const filesys = require("fs");
const path = require("path");
// body parser module parses form data into server
const body_parse = require("body-parser");
// middleware to encrypt folder structure for users : can look into DevTools
app.use('/public', express.static(path.join(__dirname, 'static')));
// allows us to parse url encoded forms
app.use(body_parse.urlencoded({extended: false}));
// using readstream with chunks in buffer with security on the path
app.get("/fitbit", (req, res) => {
const readStream = filesys.createReadStream(path.join(__dirname,'static','post_request.html'));
readStream.on('error', function(){
/*handle error*/
res.write("there is an error authenticating against fitbit api endpoint");
});
res.writeHead(200, {'Content-type' : 'text/html'});
readStream.pipe(res);
});
// bodyparser parses data and adds to the body of the request
app.get("/", (req, res, err) => {
const readStream = filesys.createReadStream(path.join(__dirname,'static','start_page.html'));
res.writeHead(200, {'Content-type' : 'text/html'});
readStream.pipe(res);
});
app.listen(3000);
HTML file for the start page, with just a button to initiate the OAuth2 process..
<body>
<button onclick="fitbitAuth()">Fitbit</button>
<script>
// define variables
var cli_id = "xxxxx";
var res_typ = "token";
var scope_typ = "activity";
var redirect = "http://localhost:3000/fitbit";
var expires = "31536000";
var prompt_var = "consent";
// upon clicking fitbit button, starting off the oauth2 authentication
function fitbitAuth() {
window.location.href = "https://www.fitbit.com/oauth2/authorize?client_id=" + cli_id + "&response_type=" + res_typ + "&scope=" + scope_typ + "&redirect_uri=" + redirect + "&expires_in=" + expires + "&prompt=" + prompt_var;
}
</script>
</body>
</html>
The redirect page, the page the user gets sent back to after consenting using his/ her data.. With just one button to initiate API call on lifetime activity stats..
<body>
<!-- action = route, method = method -->
<button type="submit" onclick="getActivityData()">Send Request</button>
<script>
// get out the accesstoken from the provided data
var url_terug = window.location.href;
var split_after = "access_token=";
var split_before = "&user_id";
var after_string = url_terug.split(split_after).pop();
var accesstoken = after_string.slice(0, after_string.indexOf(split_before));
console.log(accesstoken);
// getActivityData();
function getActivityData(){
// execute a POST request with the right parameters
var request = new XMLHttpRequest();
request.open('GET', "https://api.fitbit.com/1/user/-/activities.json");
request.setRequestHeader('Authorization', 'Bearer '+ accesstoken);
// Setup our listener to process completed requests
request.onload = function () {
// Process our return data
// status code between 200 and 300 indicates success
if (request.status >= 200 && request.status < 300) {
console.log('success!', request);
console.log(request.responseText);
// continue with API calls..
// you could set up a broader response handling if there is a use case for it
} else {
console.log('The current token request failed!');
}
};
request.send();
}
</script>
</body>

Related

How to use "Sign In With Google" together with TokenClient?

I read the information and examples from the Sign in with Google Guides and the Google Identity Services JavaScript SDK Guides and I managed to set up authorization using Tokens to Google Cloud APIs. Unfortunately, I still get a login prompt to select my Google Account every time I load the page even after the user consent has been given on first login.
I saw that requestAccessToken allows specifying a user email as hint via OverridableTokenClientConfig for the login, but even if I specify the hint I still get the login prompt every time requestAccessToken is running.
Ultimately, I want to use Sign in with Google to allow the user to automatically sign in and provide user information like email to the app. Then requestAccessToken should use that email to request the token without prompting the user again (except for the first time where the user needs to give consent to the devstorage.full_control scope).
This is the current code I'm using (to run it, you need to insert a valid clientId, bucket and object):
<html>
<head>
<!-- Google Identity Service see https://developers.google.com/identity/oauth2/web/guides/migration-to-gis#gis-and-gapi -->
<script src="https://accounts.google.com/gsi/client" onload="initTokenClient()" async defer></script>
<script>
var tokenClient;
var access_token;
var clientId = '123456789012-abcdefghijklmnopqrstuvxyz123456.apps.googleusercontent.com';
var email = 'florian.feldhaus#gmail.com'
var bucket = 'private-bucket'
var object = 'private-object.json'
function initTokenClient() {
tokenClient = google.accounts.oauth2.initTokenClient({
client_id: clientId,
scope: 'https://www.googleapis.com/auth/devstorage.full_control',
callback: (tokenResponse) => {
access_token = tokenResponse.access_token;
},
});
}
function getToken() {
// Re-entrant function to request user consent.
// Returns an access token to the callback specified in google.accounts.oauth2.initTokenClient
// Use a user gesture to call this function and obtain a new, valid access token
// when the previous token expires and a 401 status code is returned by Google API calls.
tokenClient.requestAccessToken({
hint: email
}
);
}
function getObject() {
fetch('https://storage.googleapis.com/storage/v1/b/' + bucket + '/o/' + object + '?alt=media', {
headers: {
'Authorization': 'Bearer ' + access_token
}
})
.then(response => response.json())
.then(content => console.log(content))
.catch(err => { console.log(err) });
}
</script>
</head>
<body>
<button onclick="getToken();">Get access token</button>
<button onclick="getObject()">Load Object</button>
</body>
</html>
Getting the access token always opens a login prompt like this
The login prompt can be prevented by setting an empty prompt parameter in initTokenClient. This will only prompt for the login and user consent on the first login. All further logins will use the selected account from the first login. This still briefly shows a popup with a spinning wheel which usually is gone within a second.
If someone has more information to share on how to get rid of the popup and integrate with Sign in with Google please share as a separate answer.
My full example now looks like this (removing hint and adding prompt):
<html>
<head>
<!-- Google Identity Service see https://developers.google.com/identity/oauth2/web/guides/migration-to-gis#gis-and-gapi -->
<script src="https://accounts.google.com/gsi/client" onload="initTokenClient()" async defer></script>
<script>
var tokenClient;
var access_token;
var clientId = '123456789012-abcdefghijklmnopqrstuvxyz123456.apps.googleusercontent.com';
var email = 'florian.feldhaus#gmail.com'
var bucket = 'private-bucket'
var object = 'private-object.json'
function initTokenClient() {
tokenClient = google.accounts.oauth2.initTokenClient({
client_id: clientId,
scope: 'https://www.googleapis.com/auth/devstorage.full_control',
prompt: '',
callback: (tokenResponse) => {
access_token = tokenResponse.access_token;
},
});
}
function getToken() {
// Re-entrant function to request user consent.
// Returns an access token to the callback specified in google.accounts.oauth2.initTokenClient
// Use a user gesture to call this function and obtain a new, valid access token
// when the previous token expires and a 401 status code is returned by Google API calls.
tokenClient.requestAccessToken();
}
function getObject() {
fetch('https://storage.googleapis.com/storage/v1/b/' + bucket + '/o/' + object + '?alt=media', {
headers: {
'Authorization': 'Bearer ' + access_token
}
})
.then(response => response.json())
.then(content => console.log(content))
.catch(err => { console.log(err) });
}
</script>
</head>
<body>
<button onclick="getToken();">Get access token</button>
<button onclick="getObject()">Load Object</button>
</body>
</html>

XMLHttpRequest endpoint blocked while signing S3 request because no HTTPS, eventhough everything is on HTTPS

I am trying to sign a huge video upload, because I want to upload it directly to S3. It works on localhost, but on my live site it fails to sign the request because of:
Mixed Content: The page at 'https://www.example.com/profile' was loaded
over HTTPS, but requested an insecure XMLHttpRequest endpoint
'http://www.example.com/sign_s3/?file_name=17mbvid.mp4&file_type=video/mp4'.
This request has been blocked; the content must be served over HTTPS.
I am hosting everything on heroku, every page is already using HTTPS and its not possible to open it in HTTP, because I redirect all traffic to HTTPS. I am using the letsencrypt SSL certificate.
So far I have no idea where to look, the only information I found, is that I need a valid SSL certificate, which I have.
Here is the JS function:
function getSignedRequest(file) {
var xhr = new XMLHttpRequest();
xhr.open("GET", "/sign_s3?file_name=" + file.name + "&file_type=" + file.type);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
console.log('got signed request');
var response = JSON.parse(xhr.responseText);
console.log(response);
console.log('uploadFile', response.url)
uploadFile(file, response.data, response.url);
} else {
console.log("Could not get signed URL.");
}
}
};
//console.log('send');
xhr.send();
}
Right after the error in the console I see this console log:
Could not get signed URL.
which means it fails here:
if (xhr.status === 200)
On the server:
#app.route('/sign_s3/', methods=["GET", "POST"])
#login_required
#check_confirmed
def sign_s3():
if "localhost" in request.url_root:
file_name = str(current_user.id) + "local-profil-video." + request.args.get('file_name').split(".")[-1]
else:
file_name = str(current_user.id) + "-profil-video." + request.args.get('file_name').split(".")[-1]
file_type = request.args.get('file_type')
session = boto3.Session(
aws_access_key_id=app.config['MY_AWS_ID'],
aws_secret_access_key=app.config['MY_AWS_SECRET'],
region_name='eu-central-1'
)
s3 = session.client('s3')
presigned_post = s3.generate_presigned_post(
Bucket = 'adultpatreon',
Key = 'videos/' + file_name,
Fields = {"acl": "public-read", "Content-Type": file_type},
Conditions = [
{"acl": "public-read"},
{"Content-Type": file_type}
],
ExpiresIn = 3600
)
if current_user.profile_video != None:
delete_file_from_aws("videos/", current_user.profile_video)
setattr(current_user, "profile_video", file_name)
db_session.commit()
return json.dumps({'data': presigned_post, 'url': 'https://s3.eu-central-1.amazonaws.com/mybucket/' + 'videos/' + file_name})
After many hours of researching I decided to rebuild this function and use AJAX get, which I am more familiar with. I also changed the way I pass/recieve the query string arguments to the best way, which is actually used in flask/python.
function getSignedRequest(file) {
$.ajax({
url : "/sign_s3/" + file.name + "/" + file.type,
type : "get",
success : function(response) {
console.log("success file up, follow", response);
var json_response = JSON.parse(response);
console.log(json_response);
uploadFile(file, json_response.data, json_response.url);
},
error : function(xhr) {
console.log("file up failed", xhr);
}
});
}
And on server side I changed how file.name and file.type are recieved:
# Sign request for direct file upload through client for video
#app.route('/sign_s3/<path:file_name_data>/<path:file_type_data>', methods=["GET", "POST"])
#login_required
#check_confirmed
def sign_s3(file_name_data, file_type_data):
#etc...
Now it works perfectly. I think they way I was recieving the query string arguments on the server was not correct, probably it would also work with the old getSignedRequest function (untested).

Power BI Embedded - Access Token

So I have some graphs in Power BI which I want to share with my clients.
I'm making a custom page here on my server and trying to embed those graphs using Power BI Embedded setup.
I'm following this link https://learn.microsoft.com/en-us/power-bi/developer/get-azuread-access-token
However, how do I get an access token via javascript API?
Generate EmbedToken is basically a REST API call. you can use NodeJs or AJAX to issue this request and get your EmbedToken.
For AAD auth, I can maybe refer you to ADAL.js: https://github.com/AzureAD/azure-activedirectory-library-for-js
which can help with auth against AAD
I don't think that's possible in Javascript at the moment. I tried to create access tokens in Javascript not a long time ago but failed to find a way to do that.
I ended up doing a bit of server side code (something like this https://learn.microsoft.com/en-us/power-bi/developer/walkthrough-push-data-get-token) and printed the access code to a hidden div. Then I grabbed the token with Javascript and continued with Javascript from there (created the embed token and embedded the report itself).
It might be possible to do a sort of Javascript solution with a proxy, but that's out of my expertise (the proxy has the server side code).
The only pure Javascript solution I'm aware of is the Publish to web -solution (https://learn.microsoft.com/en-us/power-bi/service-publish-to-web), but it's got some limitations and security issues.
I have already embed the Power BI reports into my web application. And also, i have faced problems while embedding report into my application but finally i embed the reports. Below is the code that will help you to get the Access token.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title></title>
<script src="https://secure.aadcdn.microsoftonline-p.com/lib/1.0.12/js/adal.min.js"></script>
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script>
window.config = {
instance: 'https://login.microsoftonline.com/',
tenant: 'common', //COMMON OR YOUR TENANT ID
clientId: '49df1bc7-db68-4fb4-91c0-6d93f770d1a4', //This is your client ID
redirectUri: 'https://login.live.com/oauth20_desktop.srf', //This is your redirect URI
callback: userSignedIn,
popUp: true
};
var ADAL = new AuthenticationContext(config);
function signIn() {
ADAL.login();
}
function userSignedIn(err, token) {
console.log('userSignedIn called');
if (!err) {
showWelcomeMessage();
ADAL.acquireToken("https://analysis.windows.net/powerbi/api", function(error, token) {
// Handle ADAL Error
if (error || !token) {
printErrorMessage('ADAL Error Occurred: ' + error);
return;
}
// Get TodoList Data
$.ajax({
type: "GET",
url: "https://api.powerbi.com/v1.0/myorg/datasets",
headers: {
'Authorization': 'Bearer ' + token,
},
}).done(function(data) {
console.log(data);
// Update the UI
$loading.hide();
}).fail(function() {
printErrorMessage('Error getting todo list data')
}).always(function() {
// Register Handlers for Buttons in Data Table
registerDataClickHandlers();
});
});
} else {
console.error("error: " + err);
}
}
function getDataSets() {
var trythis = "Bearer " + token;
var request = new XMLHttpRequest();
request.open('GET', 'https://api.powerbi.com/v1.0/myorg/datasets'); request.setRequestHeader('Authorization', trythis);
request.onreadystatechange = function() {
if (this.readyState === 4) {
console.log('Status:', this.status);
console.log('Body:', this.responseText);
}
};
request.send();
}
function showWelcomeMessage() {
var user = ADAL.getCachedUser();
var divWelcome = document.getElementById('WelcomeMessage');
divWelcome.innerHTML = "Welcome " + user.profile.name;
}
</script>
</head>
<body>
<button id="SignIn" onclick="signIn()">Sign In</button>
<h4 id="WelcomeMessage"></h4>
</body>
</html>
For more information you can go through the link that i will provide here.
Link : https://community.powerbi.com/t5/Developer/get-Access-token-using-js/m-p/352093#M10472

Ajax request to server from html page doesn't work

I made a server on NodeJs using module Express. Now I want to implement a request from html page with $.ajax by clicking a button. I want to get data from server in json format or in text format, it doesnt matter, but it doesn't work. Why?
And plus why does ajax request reload the html page while it shouldn't?
Server part:
var express = require('express');
var fs = require('fs');
var request = require('request');
var cheerio = require('cheerio');
var app = express();
var url = require("url");
app.get('/scrape', function (req, res) {
console.log("Someone made request");
url = 'http://spun.fkpkzs.ru/Level/Gorny';
request(url, function (error, response, html) {
if (!error) {
console.log("Inside request");
var $ = cheerio.load(html);
var date, waterlevel;
var json = {
time: "",
waterlevel: ""
};
json.time = $("#waterleveltable td.timestampvalue").first().text()
json.waterlevel = $("#waterleveltable td.value").first().text()
res.send(json);
console.log(json);
}
})
})
app.listen('8081')
console.log('Server started on port 8081');
exports = module.exports = app;
This is my hmlt request:
<form>
<!-- button for sending a request to server-->
<button id="button12">Scrape water height</button>
</form>
<div id="response21">
Print
<!-- div for displaying the response from server -->
</div>
<p id="p1">___!</p>
<script>
$(document).ready(function () {
$("#button12").click(function () {
console.log("Get sent.")
// Json request
$.get("http://localhost:8081/scrape", function (data)
{
console.log("Data recieved" + data);
$("#response21")
.append("Time: " + data.time)
.append("Waterlevel: " + data.waterlevel);
}, "json");
});
});
Because of the fact that your button is inside a form, the default action of clicking the button will be to load a new page. This is what causes the reload of your page.
The simplest thing you can do is a return false at the end of the click handler callback so that to prevent the reload of the page.

How to send an email from JavaScript

I want my website to have the ability to send an email without refreshing the page. So I want to use Javascript.
<form action="javascript:sendMail();" name="pmForm" id="pmForm" method="post">
Enter Friend's Email:
<input name="pmSubject" id="pmSubject" type="text" maxlength="64" style="width:98%;" />
<input name="pmSubmit" type="submit" value="Invite" />
Here is how I want to call the function, but I'm not sure what to put into the javascript function. From the research I've done I found an example that uses the mailto method, but my understanding is that doesn't actually send directly from the site.
So my question is where can I find what to put inside the JavaScript function to send an email directly from the website.
function sendMail() {
/* ...code here... */
}
You can't send an email directly with javascript.
You can, however, open the user's mail client:
window.open('mailto:test#example.com');
There are also some parameters to pre-fill the subject and the body:
window.open('mailto:test#example.com?subject=subject&body=body');
Another solution would be to do an ajax call to your server, so that the server sends the email. Be careful not to allow anyone to send any email through your server.
Indirect via Your Server - Calling 3rd Party API - secure and recommended
Your server can call the 3rd Party API. The API Keys are not exposed to client.
node.js
const axios = require('axios');
async function sendEmail(name, email, subject, message) {
const data = JSON.stringify({
"Messages": [{
"From": {"Email": "<YOUR EMAIL>", "Name": "<YOUR NAME>"},
"To": [{"Email": email, "Name": name}],
"Subject": subject,
"TextPart": message
}]
});
const config = {
method: 'post',
url: 'https://api.mailjet.com/v3.1/send',
data: data,
headers: {'Content-Type': 'application/json'},
auth: {username: '<API Key>', password: '<Secret Key>'},
};
return axios(config)
.then(function (response) {
console.log(JSON.stringify(response.data));
})
.catch(function (error) {
console.log(error);
});
}
// define your own email api which points to your server.
app.post('/api/sendemail/', function (req, res) {
const {name, email, subject, message} = req.body;
//implement your spam protection or checks.
sendEmail(name, email, subject, message);
});
and then use use fetch on client side to call your email API.
Use from email which you used to register on Mailjet. You can authenticate more addresses too. Mailjet offers a generous free tier.
Update 2023: As pointed out in the comments the method below does not work any more due to CORS
This can be only useful if you want to test sending email and to do this
visit https://api.mailjet.com/stats (yes a 404 page)
and run this code in the browser console (with the secrets populated)
Directly From Client - Calling 3rd Party API - not recommended
in short:
register for Mailjet to get an API key and Secret
use fetch to call API to send an email
Like this -
function sendMail(name, email, subject, message) {
const myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
myHeaders.set('Authorization', 'Basic ' + btoa('<API Key>'+":" +'<Secret Key>'));
const data = JSON.stringify({
"Messages": [{
"From": {"Email": "<YOUR EMAIL>", "Name": "<YOUR NAME>"},
"To": [{"Email": email, "Name": name}],
"Subject": subject,
"TextPart": message
}]
});
const requestOptions = {
method: 'POST',
headers: myHeaders,
body: data,
};
fetch("https://api.mailjet.com/v3.1/send", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
}
sendMail('Test Name',"<YOUR EMAIL>",'Test Subject','Test Message')
Note: Keep in mind that your API key is visible to anyone, so any malicious user may use your key to send out emails that can eat up your quota.
I couldn't find an answer that really satisfied the original question.
Mandrill is not desirable due to it's new pricing policy, plus it required a backend service if you wanted to keep your credentials safe.
It's often preferable to hide your email so you don't end up on any lists (the mailto solution exposes this issue, and isn't convenient for most users).
It's a hassle to set up sendMail or require a backend at all just to send an email.
I put together a simple free service that allows you to make a standard HTTP POST request to send an email. It's called PostMail, and you can simply post a form, use JavaScript or jQuery. When you sign up, it provides you with code that you can copy & paste into your website. Here are some examples:
JavaScript:
<form id="javascript_form">
<input type="text" name="subject" placeholder="Subject" />
<textarea name="text" placeholder="Message"></textarea>
<input type="submit" id="js_send" value="Send" />
</form>
<script>
//update this with your js_form selector
var form_id_js = "javascript_form";
var data_js = {
"access_token": "{your access token}" // sent after you sign up
};
function js_onSuccess() {
// remove this to avoid redirect
window.location = window.location.pathname + "?message=Email+Successfully+Sent%21&isError=0";
}
function js_onError(error) {
// remove this to avoid redirect
window.location = window.location.pathname + "?message=Email+could+not+be+sent.&isError=1";
}
var sendButton = document.getElementById("js_send");
function js_send() {
sendButton.value='Sending…';
sendButton.disabled=true;
var request = new XMLHttpRequest();
request.onreadystatechange = function() {
if (request.readyState == 4 && request.status == 200) {
js_onSuccess();
} else
if(request.readyState == 4) {
js_onError(request.response);
}
};
var subject = document.querySelector("#" + form_id_js + " [name='subject']").value;
var message = document.querySelector("#" + form_id_js + " [name='text']").value;
data_js['subject'] = subject;
data_js['text'] = message;
var params = toParams(data_js);
request.open("POST", "https://postmail.invotes.com/send", true);
request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
request.send(params);
return false;
}
sendButton.onclick = js_send;
function toParams(data_js) {
var form_data = [];
for ( var key in data_js ) {
form_data.push(encodeURIComponent(key) + "=" + encodeURIComponent(data_js[key]));
}
return form_data.join("&");
}
var js_form = document.getElementById(form_id_js);
js_form.addEventListener("submit", function (e) {
e.preventDefault();
});
</script>
jQuery:
<form id="jquery_form">
<input type="text" name="subject" placeholder="Subject" />
<textarea name="text" placeholder="Message" ></textarea>
<input type="submit" name="send" value="Send" />
</form>
<script>
//update this with your $form selector
var form_id = "jquery_form";
var data = {
"access_token": "{your access token}" // sent after you sign up
};
function onSuccess() {
// remove this to avoid redirect
window.location = window.location.pathname + "?message=Email+Successfully+Sent%21&isError=0";
}
function onError(error) {
// remove this to avoid redirect
window.location = window.location.pathname + "?message=Email+could+not+be+sent.&isError=1";
}
var sendButton = $("#" + form_id + " [name='send']");
function send() {
sendButton.val('Sending…');
sendButton.prop('disabled',true);
var subject = $("#" + form_id + " [name='subject']").val();
var message = $("#" + form_id + " [name='text']").val();
data['subject'] = subject;
data['text'] = message;
$.post('https://postmail.invotes.com/send',
data,
onSuccess
).fail(onError);
return false;
}
sendButton.on('click', send);
var $form = $("#" + form_id);
$form.submit(function( event ) {
event.preventDefault();
});
</script>
Again, in full disclosure, I created this service because I could not find a suitable answer.
I know I am wayyy too late to write an answer for this question but nevertheless I think this will be use for anybody who is thinking of sending emails out via javascript.
The first way I would suggest is using a callback to do this on the server. If you really want it to be handled using javascript folowing is what I recommend.
The easiest way I found was using smtpJs. A free library which can be used to send emails.
1.Include the script like below
<script src="https://smtpjs.com/v3/smtp.js"></script>
2. You can either send an email like this
Email.send({
Host : "smtp.yourisp.com",
Username : "username",
Password : "password",
To : 'them#website.com',
From : "you#isp.com",
Subject : "This is the subject",
Body : "And this is the body"
}).then(
message => alert(message)
);
Which is not advisable as it will display your password on the client side.Thus you can do the following which encrypt your SMTP credentials, and lock it to a single domain, and pass a secure token instead of the credentials instead.
Email.send({
SecureToken : "C973D7AD-F097-4B95-91F4-40ABC5567812",
To : 'them#website.com',
From : "you#isp.com",
Subject : "This is the subject",
Body : "And this is the body"
}).then(
message => alert(message)
);
Finally if you do not have a SMTP server you use an smtp relay service such as Elastic Email
Also here is the link to the official SmtpJS.com website where you can find all the example you need and the place where you can create your secure token.
I hope someone find this details useful. Happy coding.
You can find what to put inside the JavaScript function in this post.
function getAjax() {
try {
if (window.XMLHttpRequest) {
return new XMLHttpRequest();
} else if (window.ActiveXObject) {
try {
return new ActiveXObject('Msxml2.XMLHTTP');
} catch (try_again) {
return new ActiveXObject('Microsoft.XMLHTTP');
}
}
} catch (fail) {
return null;
}
}
function sendMail(to, subject) {
var rq = getAjax();
if (rq) {
// Success; attempt to use an Ajax request to a PHP script to send the e-mail
try {
rq.open('GET', 'sendmail.php?to=' + encodeURIComponent(to) + '&subject=' + encodeURIComponent(subject) + '&d=' + new Date().getTime().toString(), true);
rq.onreadystatechange = function () {
if (this.readyState === 4) {
if (this.status >= 400) {
// The request failed; fall back to e-mail client
window.open('mailto:' + to + '?subject=' + encodeURIComponent(subject));
}
}
};
rq.send(null);
} catch (fail) {
// Failed to open the request; fall back to e-mail client
window.open('mailto:' + to + '?subject=' + encodeURIComponent(subject));
}
} else {
// Failed to create the request; fall back to e-mail client
window.open('mailto:' + to + '?subject=' + encodeURIComponent(subject));
}
}
Provide your own PHP (or whatever language) script to send the e-mail.
I am breaking the news to you. You CAN'T send an email with JavaScript per se.
Based on the context of the OP's question, my answer above does not hold true anymore as pointed out by #KennyEvitt in the comments. Looks like you can use JavaScript as an SMTP client.
However, I have not digged deeper to find out if it's secure & cross-browser compatible enough. So, I can neither encourage nor discourage you to use it. Use at your own risk.
There seems to be a new solution at the horizon. It's called EmailJS. They claim that no server code is needed. You can request an invitation.
Update August 2016: EmailJS seems to be live already. You can send up to 200 emails per month for free and it offers subscriptions for higher volumes.
window.open('mailto:test#example.com'); as above
does nothing to hide the "test#example.com" email address from being harvested by spambots. I used to constantly run into this problem.
var recipient="test";
var at = String.fromCharCode(64);
var dotcom="example.com";
var mail="mailto:";
window.open(mail+recipient+at+dotcom);
In your sendMail() function, add an ajax call to your backend, where you can implement this on the server side.
Javascript is client-side, you cannot email with Javascript. Browser recognizes maybe only mailto: and starts your default mail client.
JavaScript can't send email from a web browser. However, stepping back from the solution you've already tried to implement, you can do something that meets the original requirement:
send an email without refreshing the page
You can use JavaScript to construct the values that the email will need and then make an AJAX request to a server resource that actually sends the email. (I don't know what server-side languages/technologies you're using, so that part is up to you.)
If you're not familiar with AJAX, a quick Google search will give you a lot of information. Generally you can get it up and running quickly with jQuery's $.ajax() function. You just need to have a page on the server that can be called in the request.
It seems like one 'answer' to this is to implement an SMPT client. See email.js for a JavaScript library with an SMTP client.
Here's the GitHub repo for the SMTP client. Based on the repo's README, it appears that various shims or polyfills may be required depending on the client browser, but overall it does certainly seem feasible (if not actually significantly accomplished), tho not in a way that's easily describable by even a reasonably-long answer here.
There is a combination service. You can combine the above listed solutions like mandrill with a service EmailJS, which can make the system more secure.
They have not yet started the service though.
Another way to send email from JavaScript, is to use directtomx.com as follows;
Email = {
Send : function (to,from,subject,body,apikey)
{
if (apikey == undefined)
{
apikey = Email.apikey;
}
var nocache= Math.floor((Math.random() * 1000000) + 1);
var strUrl = "http://directtomx.azurewebsites.net/mx.asmx/Send?";
strUrl += "apikey=" + apikey;
strUrl += "&from=" + from;
strUrl += "&to=" + to;
strUrl += "&subject=" + encodeURIComponent(subject);
strUrl += "&body=" + encodeURIComponent(body);
strUrl += "&cachebuster=" + nocache;
Email.addScript(strUrl);
},
apikey : "",
addScript : function(src){
var s = document.createElement( 'link' );
s.setAttribute( 'rel', 'stylesheet' );
s.setAttribute( 'type', 'text/xml' );
s.setAttribute( 'href', src);
document.body.appendChild( s );
}
};
Then call it from your page as follows;
window.onload = function(){
Email.apikey = "-- Your api key ---";
Email.Send("to#domain.com","from#domain.com","Sent","Worked!");
}
There is not a straight answer to your question as we can not send email only using javascript, but there are ways to use javascript to send emails for us:
1) using an api to and call the api via javascript to send the email for us, for example https://www.emailjs.com says that you can use such a code below to call their api after some setting:
var service_id = 'my_mandrill';
var template_id = 'feedback';
var template_params = {
name: 'John',
reply_email: 'john#doe.com',
message: 'This is awesome!'
};
emailjs.send(service_id,template_id,template_params);
2) create a backend code to send an email for you, you can use any backend framework to do it for you.
3) using something like:
window.open('mailto:me#http://stackoverflow.com/');
which will open your email application, this might get into blocked popup in your browser.
In general, sending an email is a server task, so should be done in backend languages, but we can use javascript to collect the data which is needed and send it to the server or api, also we can use third parities application and open them via the browser using javascript as mentioned above.
If and only if i had to use some js library, i would do that with SMTPJs library.It offers encryption to your credentials such as username, password etc.
The short answer is that you can't do it using JavaScript alone. You'd need a server-side handler to connect with the SMTP server to actually send the mail. There are many simple mail scripts online, such as this one for PHP:
Use Ajax to send request to the PHP script ,check that required field are not empty or incorrect using js also keep a record of mail send by whom from your server.
function sendMail() is good for doing that.
Check for any error caught while mailing from your script and take appropriate action.
For resolving it for example if the mail address is incorrect or mail is not send due to server problem or it's in queue in such condition report it to user immediately and prevent multi sending same email again and again.
Get response from your script Using jQuery GET and POST
$.get(URL,callback);
$.post(URL,callback);
Since these all are wonderful infos there's a little api called Mandrill to send mails from javascript and it works perfectly. You can give it a shot. Here's a little tutorial for the start.
Full AntiSpam version:
<div class="at">info<i class="fa fa-at"></i>google.com</div>
OR
<div class="at">info#google.com</div>
<style>
.at {
color: blue;
cursor: pointer;
}
.at:hover {
color: red;
}
</style>
<script>
const el33 = document.querySelector(".at");
el33.onclick = () => {
let recipient="info";
let at = String.fromCharCode(64);
let dotcom="google.com";
let mail="mailto:";
window.open(mail+recipient+at+dotcom);
}
</script>
Send an email using the JavaScript or jQuery
var ConvertedFileStream;
var g_recipient;
var g_subject;
var g_body;
var g_attachmentname;
function SendMailItem(p_recipient, p_subject, p_body, p_file, p_attachmentname, progressSymbol) {
// Email address of the recipient
g_recipient = p_recipient;
// Subject line of an email
g_subject = p_subject;
// Body description of an email
g_body = p_body;
// attachments of an email
g_attachmentname = p_attachmentname;
SendC360Email(g_recipient, g_subject, g_body, g_attachmentname);
}
function SendC360Email(g_recipient, g_subject, g_body, g_attachmentname) {
var flag = confirm('Would you like continue with email');
if (flag == true) {
try {
//p_file = g_attachmentname;
//var FileExtension = p_file.substring(p_file.lastIndexOf(".") + 1);
// FileExtension = FileExtension.toUpperCase();
//alert(FileExtension);
SendMailHere = true;
//if (FileExtension != "PDF") {
// if (confirm('Convert to PDF?')) {
// SendMailHere = false;
// }
//}
if (SendMailHere) {
var objO = new ActiveXObject('Outlook.Application');
var objNS = objO.GetNameSpace('MAPI');
var mItm = objO.CreateItem(0);
if (g_recipient.length > 0) {
mItm.To = g_recipient;
}
mItm.Subject = g_subject;
// if there is only one attachment
// p_file = g_attachmentname;
// mAts.add(p_file, 1, g_body.length + 1, g_attachmentname);
// If there are multiple attachment files
//Split the files names
var arrFileName = g_attachmentname.split(";");
// alert(g_attachmentname);
//alert(arrFileName.length);
var mAts = mItm.Attachments;
for (var i = 0; i < arrFileName.length; i++)
{
//alert(arrFileName[i]);
p_file = arrFileName[i];
if (p_file.length > 0)
{
//mAts.add(p_file, 1, g_body.length + 1, g_attachmentname);
mAts.add(p_file, i, g_body.length + 1, p_file);
}
}
mItm.Display();
mItm.Body = g_body;
mItm.GetInspector.WindowState = 2;
}
//hideProgressDiv();
} catch (e) {
//debugger;
//hideProgressDiv();
alert('Unable to send email. Please check the following: \n' +
'1. Microsoft Outlook is installed.\n' +
'2. In IE the SharePoint Site is trusted.\n' +
'3. In IE the setting for Initialize and Script ActiveX controls not marked as safe is Enabled in the Trusted zone.');
}
}
}

Categories

Resources