Archive
Getting Started With #SmtpJs & #React
Getting Started With SmtpJs & React
Introduction
My name is Alec Dilanchian and I am an avid programmer who enjoys working on side projects and creating cool tools. These projects all come to life on Twitch, a live streaming platform where I stream myself programming projects in 28 days from start to launch (If this sounds interesting to you, please consider checking out my stream @ https://www.twitch.tv/pixelogicdev).
I recently started a new project called FocusBlock, which can be found here. FocusBlock is an open source tool that helps you time block a task and contacts a designated person, via email, if you do not finish your task in the assigned time. Think of it like a pomodoro timer with a way to automatically gain assistance if needed. I needed a tool that would automatically send an email, via the client, if their timer ended before they finished their task. I came across SmtpJs. This component seemed straight forward and extrmemely easy to use. There was just one caveat, FocusBlock’s client side is being created with React. I wanted to keep everything as native as possible, so I challenged myself to create a very simple React component out of this awesome tool. In this article, I want to show you how easy it can be to do just this!
Download The Source Code
The component needed to get the basic logic for SmtpJs can be found @ https://wwww.smtpjs.com. When you reach the home page of the site you will want to select the “Download” button. This will download the source code needed in order for you to get started with SmtpJs. It should just be one .js
file as of version 2.0.1.
Create a React Component
Once you have your source code, you are all set to get started on your React component. If you are unfamiliar with React, I would suggest checking out their guide here to gain much needed knowledge on how components work and what the library as a whole does. Do begin creating a React component, I start by adding a new folder of whatever the component will be called. In this instance I called my component SmtpService
. This will hold any and all of our component logic. The next step should be straight forward. Go ahead and create a file called SmtpService.js
. This will be the entry point of your component and where we will house all of its logic.
Next we will want to ge the basic layout of our React component. This is done with the following boilerplate code:
import { Component } from 'react';
class SmtpService extends Component {
/* https://smtpjs.com/ */
/* SmtpJS.com - v2.0.1 */
}
export default SmtpService;
Don’t forget to give credit to SmtpJs for their source code!
Add The SmtpJs Source Code
Once our barebones React component is setup, its time to add the soruce code of SmtpJs. This is as easy as copying and pasting it from that .js
file you downloaded in step one. If your React app is already running, you will notice a lot of syntax errors that the linter is complaining about. Have no fear! These are easy changes that can be fixed.
Tweaking Methods
SmtpJs has multiple methods that are key for its functionality. We need to make sure we are abiding by our component’s rules and might as well convert it to JavaScript ES6 while we are at it!
I will demonstrate one method change which is identical for every other method in the code. Lets work with the send
method. You are orignally given send: function (e, o, t, n, a, s, r, c) { /* Code */ );
. In React, these methods are not recogonized using that syntax. To abide by ES6 and React, all you have to do is change the format to this: send = (e, o, t, n, a, s, r, c) => { /* Code */};
. There is a very slight difference.
Changing var
to let
This step is just a simple ES6 change. Since all of our properties are only going to be accessed within their respective methods, we want to make sure that they do not hold a global scope. At this point, change any var
to let
and you are golden.
A Bit of Refactoring
While the source code of the project came to us as a minified file (from the looks of it), it makes it almost illegible. For this we want to make quite a few changes. At this point in the article, I am going to just post the rest of the source code. Feel free to compare the differences! Just as a note, these changes were not React specific:
send = (e, o, t, n, a, s, r, c) => {
let d = Math.floor(1e6 * Math.random() + 1);
let i = `From=${e}&to=${o}&Subject=${encodeURIComponent(
t
)}&Body=${encodeURIComponent(n)}`;
if (!a.token) {
i += `&Host=${a}&Username=${s}&Password=${r}&Action=Send`;
} else {
i += `&SecureToken=${a.token}&Action=SendFromStored`;
c = a.callback;
}
i += '&cachebuster=' + d;
this.ajaxPost('https://smtpjs.com/v2/smtp.aspx?', i, c);
};
sendWithAttachment = (e, o, t, n, a, s, r, c, d) => {
let i = Math.floor(1e6 * Math.random() + 1);
let m = `From=${e}&to=${o}&Subject=${encodeURIComponent(
t
)}&Body=${encodeURIComponent(n)}&Attachment=${encodeURIComponent(c)}`;
if (!a.token) {
m += `&Host=${a}&Username=${s}&Password=${r}&Action=Send`;
} else {
m += `&SecureToken=${a.token}&Action=SendFromStored`;
}
m += `&cachebuster=${i}`;
this.ajaxPost('https://smtpjs.com/v2/smtp.aspx?', m, d);
};
ajaxPost = (e, o, t) => {
let n = this.createCORSRequest('POST', e);
n.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
n.onload = () => {
let e = n.responseText;
if (t) t(e);
};
n.send(o);
};
ajax = (e, o) => {
let t = this.createCORSRequest('GET', e);
t.onload = () => {
let e = t.responseText;
if (o) o(e);
};
t.send();
};
createCORSRequest = (e, o) => {
let t = new XMLHttpRequest();
return (
'withCredentials' in t
? t.open(e, o, !0)
: 'undefined' !== typeof XDomainRequest
? (t = new XDomainRequest()).open(e, o)
: (t = null),
t
);
};
Send An Email
Once you are done with your component, you are free to utilize it like any other React component. Import it where you need it, and then use it:
import SmtpService from 'My/File/Path/SmtpService';
...
sendEmail = () => {
let sender = new SmtpService();
sender.send(...);
};
Conclusion
I want to give a huge shout out to the folks who created SmtpJs and thank them for the awesome and light weight component they had created to send out emails through the client side. I had a blast converting this into a React component and I hope this has helped get you started! I do want to inform you that there are many more changes that can be made to make this an even better component, but I will leave that up to you!
Please feel free to get in contact with me about this or anything else through:
Twitch
Twitter
Email
***********
Thanks Alec for this great guest post, if you’d like to appear in this blog with some tips and tricks on SMTP.JS or another of our components, then drop us a comment or email.
Managing #stripe disputes in #connected accounts
If you run a platform in Stripe, then you are ultimately accountable for the accounts that you connect on the platform. So if you get a few bad apples, you need to find a way to weed them out.
Lets start with some code to list all connected accounts:
publicstaticstring ListAllConnectedAccounts(){var wc = new WebClient();string strResult;try{ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;var myCreds = new NetworkCredential(SecretKey, “”);wc.Credentials = myCreds;conststring strUrl = “https://api.stripe.com/v1/accounts?limit=100”;wc.Headers[“Content-Type”] = “application/x-www-form-urlencoded”;strResult = wc.DownloadString(strUrl);}catch (WebException ex){strResult = new StreamReader(ex.Response.GetResponseStream()).ReadToEnd();}return strResult;}
publicstaticstring ListCustomerDisputes(string stripeAccount){var wc = new WebClient();try{ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;var myCreds = new NetworkCredential(SecretKey, “”);wc.Credentials = myCreds;conststring strUrl = “https://api.stripe.com/v1/disputes?limit=100”;wc.Headers[“Stripe-Account”] = stripeAccount;wc.Headers[“Content-Type”] = “application/x-www-form-urlencoded”;return wc.DownloadString(strUrl);}catch (WebException ex){return new StreamReader(ex.Response.GetResponseStream()).ReadToEnd();}}
public static string DeAuthorize(string stripeAccount){/*-u sk_xxxxxx: \-d client_id=ca_xxxxxxx \-d stripe_user_id=acct_1BkSmpCTl4PWCQPr*/var wc = new WebClient();var strClientId = ConfigurationManager.AppSettings[“stripe_client_id”];try{ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;String userName = SecretKey;String passWord = “”;string credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes(userName + “:” + passWord));wc.Headers[HttpRequestHeader.Authorization] = “Basic ” + credentials;var strUrl = “https://connect.stripe.com/oauth/deauthorize”;var strPostData = “client_id=” + strClientId;strPostData += “&stripe_user_id=” + stripeAccount;wc.Headers[“Content-Type”] = “application/x-www-form-urlencoded”;return wc.UploadString(strUrl,strPostData);}catch (WebException ex){returnnew StreamReader(ex.Response.GetResponseStream()).ReadToEnd();}}
Understanding #Closures in Javascript
Closures are quite an advanced feature of Javascript, but you really need to understand them whenever you need to do things like looping through asynchronous operations.
A typical use case is if you wanted to do many Ajax calls in a loop, and you find that the wrong variable value gets sent through, because by the time the Ajax returns the loop has already completed.
Here is a simplified example to demonstrate the problem, I’m using setTimeout instead of Ajax, to make the code more simple;
var arr = [1,2,3,4,5];
for(var i in arr)
{
setTimeout(function()
{
console.log(arr[i])
}, 500);
}
You may think, on first glance, that this code is going to create the output 1 2 3 4 5, but instead, it actually outputs 5 5 5 5 5 ? – here’s the solution:
for(var i in arr)
{
(function(i){
setTimeout(function()
{
console.log(arr[i])
}, 500)})(i);
}
Here, the setTimeout is wrapped in a (function(i){ … })(i) closure, which copies the value of i to the local scope of an inner function. so “i” inside the closure is of different scope to “i” in the for loop, and is in fact a different variable in memory.
Common #SMTP Hosts and #SSL/TLS Settings
A list of common SMTP servers and their SMTP Port and SSL settings from SMTPJS
#SQL Hashbytes compatible code in C#
The SQL function hashbytes allows you to hash strings directly in the database; by using something such as;
select hashbytes(‘MD5′,’hello world’)
which returns 0x5EB63BBBE01EEED093CB22BB8F5ACDC3
But if you want to compare this string with a hash created on the server by C#, then you’ll need to get it into the right format – where you could use this code here:
public static string HashBytes(string valueToHash)
{
HashAlgorithm hasher = new MD5CryptoServiceProvider();
Byte[] valueToHashAsByte = Encoding.UTF8.GetBytes(String.Concat(valueToHash, SaltValue));
Byte[] returnBytes = hasher.ComputeHash(valueToHashAsByte);
StringBuilder hex = new StringBuilder(returnBytes.Length * 2);
foreach (byte b in returnBytes) hex.AppendFormat(“{0:x2}”, b);
return “0x” + hex.ToString().ToUpper();
}
Helo command rejected: need fully-qualified hostname
When sending email from C#, if you ever get the error “Helo command rejected: need fully-qualified hostname”, you may end up scratching your head, because there is no easy way to change what gets sent in the HELO command from the SMTPClient class.
You, can however, use reflection to override what the SmtpClient class sends. here I have hard-coded “www.smtpjs.com” – because this code is specifically for this project.
You need to subclass SMTPClient as SMTPClientEx, and override the private properties localHostName and clientDomain as follows;
using System.Net.Mail;
using System.Reflection;/// <inheritdoc />
/// <summary>
/// Subclass of Smtpclient, with overridden HELO
/// </summary>
public class SmtpClientEx : SmtpClient
{public SmtpClientEx()
{
Initialize();
}private void Initialize()
{
const string strHelo = “www.smtpjs.com”;
var tSmtpClient = typeof(SmtpClient);
var localHostName = tSmtpClient.GetField(“localHostName”, BindingFlags.Instance | BindingFlags.NonPublic);
if (localHostName != null) localHostName.SetValue(this,strHelo);
var clientName = tSmtpClient.GetField(“clientDomain”, BindingFlags.Instance | BindingFlags.NonPublic);
if (clientName != null) clientName.SetValue(this, strHelo);
}
}
Automate “Get Latest Version” from Visual Studio Team Services #VSTS
If you use Visual Studio Team Services – previously known as “Visual Studio Online” to manage your source control, and you find yourself frequently exporting zip files, and copying them to deployment, you might be pleased to know there is an extensive API that allows you do a “Get Latest Version” from C#
So, first off you need to create an app with VSTS here;
https://app.vsaex.visualstudio.com/app/register
You’ll need to have a publicly accessible HTTPS website for the callback. I’ve just used https://<mydomain>/callback.aspx – I selected all the available scopes, but you can be more selective.
Once registered, you’ll get your Oauth credentials, and slot them into your web.config
<appSettings>
<add key=”app_id” value=”….”/>
<add key=”app_secret” value=”….”/>
<add key=”client_secret” value=”…..”/>
<add key=”Authorize_URL” value=”https://app.vssps.visualstudio.com/oauth2/authorize?mkt=en-US”/>
<add key=”Access_Token_URL” value=”https://app.vssps.visualstudio.com/oauth2/token?mkt=en-US”/>
<add key=”Scopes” value=”vso.build_execute vso.code_full vso.code_status vso.codesearch vso.connected_server vso.dashboards vso.dashboards_manage vso.entitlements vso.extension.data_write vso.extension_manage vso.gallery_acquire vso.gallery_manage vso.graph_manage vso.identity_manage vso.loadtest_write vso.machinegroup_manage vso.memberentitlementmanagement_write vso.notification_diagnostics vso.notification_manage vso.packaging_manage vso.profile_write vso.project_manage vso.release_manage vso.security_manage vso.serviceendpoint_manage vso.symbols_manage vso.taskgroups_manage vso.test_write vso.wiki_write vso.work_full vso.workitemsearch”/>
<add key=”RemoteLogCat” value=”…..”></add>
<add key=”RemoteScope” value=”$/….”></add>
<add key=”LocalWorkSpace” value=”F:\….\”></add>
<add key=”accountName” value=”…..”></add>
<add key=”projectName” value=”…..”></add>
</appSettings>
I’ve removed sensitive data above, but each setting is as follows:
- app_id, app_secret, client_secret – Displated after creating your app on VSTS
- RemoteLogCat – optional, from RemoteLogCat.com
- RemoteScope – The path where the root of your website resides on TFS
- LocalWorkSpace – The file path where the website will be downloaded to locally
- accountName – your account on VSTS
- projectName – the project within your account on VSTS
Then, the first step is to request consent to access your account on VSTS, which you can do a redirect link as follows;
var strUrl = “https://app.vssps.visualstudio.com/oauth2/authorize”;strUrl += “?client_id=” + ConfigurationManager.AppSettings[“app_id”];strUrl += “&response_type=Assertion”;strUrl += “&state=any”;strUrl += “&scope=” + ConfigurationManager.AppSettings[“Scopes”];strUrl += “&redirect_uri=https://…./callback.aspx”;Response.Redirect(strUrl);

var strCode = Request.QueryString[“code”];var strClientSecret = ConfigurationManager.AppSettings[“client_secret”];var strCallbackUrl = “https://…./callback.aspx”;var strTokenUrl = “https://app.vssps.visualstudio.com/oauth2/token”;var strPostData = GenerateRequestPostData(strClientSecret, strCode, strCallbackUrl);var wc = new WebClient();wc.Headers[“Content-Type”] = “application/x-www-form-urlencoded”;try{var strJson = wc.UploadString(strTokenUrl, strPostData);Response.Write(strJson);Response.Write(“<hr>”);var jObject = JObject.Parse(strJson);var strAccessCode = jObject[“access_token”].ToString();//BuildLocalWorkSpaceTree(strAccessCode);//GetLastChangeSet(strAccessCode);}catch(WebException ex){var resp = new StreamReader(ex.Response.GetResponseStream()).ReadToEnd();Response.Write(resp);}
privatestaticstring GenerateRequestPostData(string appSecret, string authCode, string callbackUrl){return String.Format(“client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&client_assertion={0}&grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion={1}&redirect_uri={2}”,HttpUtility.UrlEncode(appSecret),HttpUtility.UrlEncode(authCode),callbackUrl);}
privatevoid BuildLocalWorkSpaceTree(string bearer){var strLocalWorkspace = ConfigurationManager.AppSettings[“LocalWorkSpace”];var strAccountName = ConfigurationManager.AppSettings[“accountName”];var strRemoteScope = ConfigurationManager.AppSettings[“RemoteScope”];DeleteAllFilesAndFoldersInPath(strLocalWorkspace);var strItemsUrl = “https://{0}.visualstudio.com/_apis/tfvc/items?scopePath={1}&recursionLevel=Full&api-version=5.0-preview.1”;strItemsUrl = string.Format(strItemsUrl, strAccountName, strRemoteScope);var wc = new WebClient();wc.Headers[“Authorization”] = “Bearer ” + bearer;var strItemsJson = wc.DownloadString(strItemsUrl);Response.Write(“<hr>”);var jObject = JObject.Parse(strItemsJson);foreach (var jItem in jObject[“value”]){var strRemotePath = jItem[“path”].ToString();var strLocalPath = strRemotePath.Replace(strRemoteScope, strLocalWorkspace).Replace(“/”, @”\”);Response.Write(“Creating ” + strLocalPath + “<br>”);Response.Flush();if (jItem[“isFolder”] != null){Directory.CreateDirectory(strLocalPath);}else{var strItemUrl = “https://{0}.visualstudio.com/_apis/tfvc/items?download=true&path={1}&api-version=5.0-preview.1”;strItemUrl = string.Format(strItemUrl, strAccountName, HttpUtility.UrlEncode(strRemotePath));var raw = wc.DownloadData(strItemUrl);File.WriteAllBytes(strLocalPath,raw);}}}
Remote #ErrorLogging in C#
If you are running a C# Application on a client’s machine, and can’t run the debugger on it, then instead of asking your client to send you log files whenever something goes wrong, you can use a remote logging service to record error events, and view them, and even act on them before the client complains.
This example uses RemoteLogCat.com – a logging service designed for Android, but works equally well in C# / .NET. You will need to have an API Key, and store it as a setting as “RemoteLogCat” in your web.config / app.config
public class Logging{public static string key = ConfigurationManager.AppSettings[“RemoteLogCat”];public static void Log(string channel, string log){var strUrl = “http://www.remotelogcat.com/log.php?apikey={0}&channel={1}&log={2}”;strUrl = string.Format(strUrl, key, channel, log);var wc = new WebClient();wc.DownloadString(strUrl);}}
Logging.Log(“MyApp”,”Your Error”)
#ImageRecognition #API with REST webservice
Image Recognition API
This Image Recognition API allows images to be tagged with a label to describe the content of the image, and a confidence score percentage to indicate the level of trust in the algorithm’s judgement. View our homepage at http://imagerecognition.apixml.net
Image Recognition Web Service
The API endpoint can be accessed via this url:
http://imagerecognition.apixml.net/api.asmx
It requires an API Key, which can be applied for via this url:
Recognise
The first API endpoint is http://imagerecognition.apixml.net/api.asmx?op=Recognise
It accepts a url to an image, for example “https://www.argospetinsurance.co.uk/assets/uploads/2017/12/cat-pet-animal-domestic-104827-1024×680.jpeg”
And returns a result as follows;
<RecogntionResult xmlns:xsd=”http://www.w3.org/2001/XMLSchema” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xmlns=”http://imagerecognition.apixml.net/”> <Label>Egyptian cat</Label> <Confidence>3.63228369</Confidence> </RecogntionResult> |
Urls must be publicly accessible, you cannot use localhost urls, or intranet addresses. |
RecogniseFromBase64
The next API Endpoint is http://imagerecognition.apixml.net/api.asmx?op=RecogniseFromBase64
It accepts a base64 encoded string containing the image, you must also provide the image format, such as “jpg”, “png”, “bmp” etc.
It returns a result as follows;
<RecogntionResult xmlns:xsd=”http://www.w3.org/2001/XMLSchema” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xmlns=”http://imagerecognition.apixml.net/”> <Label>Egyptian cat</Label> <Confidence>3.63228369</Confidence> </RecogntionResult> |
OCR Web Service
Optical character recognition converts an image containing text to the text itself, a microsite for this service can be reviewed at http://ocr.apixml.net/ , here, there are two API endpoints exposed
ProcessUrl
Extract text from an image that is available on the internet via a Url. It’s endpoint is here
http://ocr.apixml.net/ocr.asmx?op=ProcessUrl
Urls must be publicly accessible, you cannot use localhost urls, or intranet addresses. |
ProcessBase64
Extract text from an image which has been base64 encoded. You also require a file extension (png/jpg/etc) to indicate the format. It’s endpoint is here;
http://ocr.apixml.net/ocr.asmx?op=ProcessBase64
By default, this service will assume a single line of text, rather than a page of text, in order to change this default behavior, or to customise it to your needs, then you can use the “extraArguments” parameter to fine-tune the OCR operation. The full list of these possible parameters are available on http://ocr.apixml.net/ |
RESOURCES
Contact information
This software is designed by Infinite Loop Development Ltd (http://www.infiniteloop.ie) and is subject to change. If you would like assistance with custom software development work, please contact us below;
-
info@infiniteloop.ie
-
+44 28 71226151
-
Twitter: @webtropy
#ImageRecognition in C# using #tensorflow #inception
Ever been faced with that situation, where you are confronted with fluffy grey animal, with four legs, whiskers, big ears and you just have no idea what it is ?
Never fear, with Artifical intelligence, you can now tell, with 12% confidence, that this is infact a tabby cat!
Ok, in fairness, what this is going to be used for is image tagging, so that a given image can be tagged based on image contents with no other context. So part of a bigger project.
Anyway, This is based on EMGU, and the Inception TensorFlow model. Which I have packaged into a web service.
You need to install the following nuget packages
Install-Package Emgu.TF
Install-Package EMGU.TF.MODELS
Then, ensuring your application is running in 64 bit mode (x86 doesn’t cut it!)
Run the code;
Inception inceptionGraph = new Inception(null, new string[] { Server.MapPath(@”models\tensorflow_inception_graph.pb”),
Server.MapPath(@”models\imagenet_comp_graph_label_strings.txt”) });
Tensor imageTensor = ImageIO.ReadTensorFromImageFile(fileName, 224, 224, 128.0f, 1.0f / 128.0f);float[] probability = inceptionGraph.Recognize(imageTensor);
Where filename is a local image file of our trusty moggie, and the output is an array of floats corresponding to the likelyhood of the image matchine one of the labels in inceptionGraph.labels
The 224, 224 bit is still a bit of dark magic to me, and I’d love someone to explain what those are!