{"id":187,"date":"2014-02-18T10:15:48","date_gmt":"2014-02-18T10:15:48","guid":{"rendered":"http:\/\/nikola-breznjak.com\/blog\/?p=187"},"modified":"2015-08-10T07:11:06","modified_gmt":"2015-08-10T07:11:06","slug":"using-casperjs-on-webfaction-to-automatically-send-emails-with-attached-images-via-gmail","status":"publish","type":"post","link":"https:\/\/nikola-breznjak.com\/blog\/javascript\/nodejs\/using-casperjs-on-webfaction-to-automatically-send-emails-with-attached-images-via-gmail\/","title":{"rendered":"Using CasperJS on Webfaction to automatically send emails with attached images via Gmail"},"content":{"rendered":"<h2>Why?<\/h2>\n<p>Recently I had to make a script which runs once per week and gathers images of an admin interface (login required) and sends it to its manager by email for quick overview. This is great because it saves the manager&#8217;s time as he doesn&#8217;t have to login to the website and click through all of the graphs and wait for them to load, instead he gets a weekly (<a href=\"http:\/\/www.urbandictionary.com\/define.php?term=YMMV\">YMMV<\/a>) summary. The site was hosted on <a href=\"http:\/\/www.webfaction.com?affiliate=hitman666\">Webfaction<\/a>, which, as it turns out,\u00a0is a cool web host (haven&#8217;t come across it before) because it allows you to compile source code and run custom binaries.<\/p>\n<h2>How?<\/h2>\n<p>The task of automatically logging in the admin dashboard and taking screenshots \u00a0proved to be an excellent job for <a href=\"http:\/\/casperjs.org\/\">CasperJS<\/a>, an open source navigation scripting &amp; testing utility written in Javascript for the <a href=\"http:\/\/phantomjs.org\/\">PhantomJS<\/a> WebKit headless browser.<\/p>\n<h2>Installation<\/h2>\n<p>In order to run CasperJS scripts, you need to have <a href=\"http:\/\/nodejs.org\/\">NodeJS<\/a> installed. Installing NodeJS on Webfaction is as straightforward as it can get, as it&#8217;s done via their control panel in the Applications tab, as shown on the illustration below:<br \/>\n<a style=\"line-height: 1.5;\" href=\"http:\/\/nikola-breznjak.com\/blog\/wp-content\/uploads\/2014\/02\/webfactionNodeInstall.jpg\" rel=\"lightbox[187]\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-190\" src=\"http:\/\/nikola-breznjak.com\/blog\/wp-content\/uploads\/2014\/02\/webfactionNodeInstall-300x247.jpg\" alt=\"webfactionNodeInstall\" width=\"300\" height=\"247\" srcset=\"https:\/\/nikola-breznjak.com\/blog\/wp-content\/uploads\/2014\/02\/webfactionNodeInstall-300x247.jpg 300w, https:\/\/nikola-breznjak.com\/blog\/wp-content\/uploads\/2014\/02\/webfactionNodeInstall.jpg 1004w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>It&#8217;s useful to put NodeJS executable in your path because then you can run <strong>node<\/strong> from any folder. You can do this by going to your\u00a0NodeJS application\u2019s bin directory and execute the following command:<\/p>\n<pre class=\"lang:default decode:true\">export PATH=$PATH:$PWD\/bin\/<\/pre>\n<p>Installing CasperJS is easy via <a href=\"https:\/\/www.npmjs.org\/\">npm <\/a>(Node package manager):<\/p>\n<pre class=\"lang:default decode:true\">npm install -g casperjs<\/pre>\n<p>However, \u00a0in order for CasperJS to work, you need to install <a href=\"http:\/\/phantomjs.org\/\">PhantomJS<\/a>\u00a0and you can do it by cloning it from its GitHub repository and running the build.sh script:<\/p>\n<pre class=\"lang:default decode:true\">mkdir -p $HOME\/src\r\n\r\ncd $HOME\/src\r\n\r\ngit clone git:\/\/github.com\/ariya\/phantomjs.git &amp;&amp; cd phantomjs\r\n\r\ngit checkout 1.5\r\n\r\n.\/build.sh\r\n\r\ncp $HOME\/src\/phantomjs\/bin\/phantomjs $HOME\/bin<\/pre>\n<p>To test if PhantomJS has been successfully installed you can run:<\/p>\n<pre class=\"lang:default decode:true\">phantomjs --version<\/pre>\n<p>To have the binaries in my path every time I log in\u00a0I added this alias to\u00a0my <strong>.bashrc<\/strong>:<\/p>\n<pre class=\"lang:default decode:true\">alias nodeset=\"export PATH=$PATH:\/home\/webapp\/node\/bin:\/home\/webapp\/bin\"<\/pre>\n<p><span style=\"line-height: 1.5;\">and my <strong>.bash_profile<\/strong> looks like this:<\/span><\/p>\n<pre class=\"lang:default decode:true\"># User specific environment and startup programs\r\nPATH=$PATH:$HOME\/bin\r\nexport PATH\r\nnodeset<\/pre>\n<h2>CasperJS script for automatically saving images<\/h2>\n<pre class=\"lang:js decode:true\">var casper = require(\"casper\").create({\r\n\tverbose: false,\r\n\tlogLevel: 'debug'\r\n});\r\n\r\nvar url = \"http:\/\/your-app.com\/\", \r\n\tsaveDir = \"\/home\/app\/savedImages\";\r\n\r\ncasper.start(url, function() {\r\n\tthis.fill('form#fm_login', {\r\n        'username':    'username',\r\n        'password':    'password',\r\n    });\r\n\r\n    this.echo(\"I filled the form\");\r\n});\r\n\r\ncasper.then(function(){\r\n\tthis.click('#btn_login');\r\n\tthis.echo(\"I'm, logging in\");\r\n});\r\n\r\n\/\/first graph fetch\r\ncasper.thenOpen(\"http:\/\/your-app.com\/graph_1\", function(){\r\n    this.wait(3000, function() {\r\n        this.echo(\"I've waited for 3 seconds for the graphs to load.\");\r\n\r\n        casper.then(function(){\r\n            var fileName = saveDir + '\/graph_1.png';\r\n            this.viewport(1920, 1080);\r\n            this.captureSelector(fileName, '#page_content');\r\n            this.echo('first snapshot taken');\r\n        });\r\n    }); \r\n});\r\n\r\ncasper.run(function() {\r\n    this.echo('done').exit();\r\n});<\/pre>\n<p>First I initialize casper and set few variables (url, saveDir &#8211; note that it has to be full path). Then I start casper by visiting the passed in <strong>url<\/strong> and fill the login form by using caspers <strong>fill()<\/strong> function. After that I click on the login button and woila &#8211; I&#8217;m logged in. After that I open up the link with the graph and wait 3 seconds for the graph to load, and then I save the selected area by using the\u00a0<strong>captureSelector()\u00a0<\/strong>function and a CSS selector of the area I want to save.<\/p>\n<h2>NodeJS script for automatically sending email with attachment via Gmail SMTP<\/h2>\n<p>This node script uses <a href=\"https:\/\/github.com\/andris9\/Nodemailer\">nodemailer <\/a>which can be installed using npm:<\/p>\n<pre class=\"lang:default decode:true\">node install -g nodemailer<\/pre>\n<p>This script uses Gmail SMTP (if you want to test it make sure to enter correct Gmail account credentials), but nodemailer offers <a href=\"https:\/\/github.com\/andris9\/Nodemailer\">many more<\/a>\u00a0options for sending the email. The simple email sending script is here:<\/p>\n<pre class=\"lang:js decode:true\">var nodemailer = require(\"nodemailer\");\r\nvar rootFolder = \"\/home\/app\/savedImages\/\";\r\n\/\/ create reusable transport method (opens pool of SMTP connections)\r\nvar smtpTransport = nodemailer.createTransport(\"SMTP\",{\r\n    service: \"Gmail\",\r\n    auth: {\r\n        user: \"your.gmail.account@gmail.com\",\r\n        pass: \"your.gmail.pass\"\r\n    }\r\n});\r\n\r\n\/\/ setup e-mail data with unicode symbols\r\nvar mailOptions = {\r\n    from: \"Automatic Graph Sender &lt;your.gmail.accoun@gmail.com&gt;\", \/\/ sender address\r\n    to: \"the.manager@gmail.com\", \/\/ list of receivers\r\n    subject: \"Automatic Graph Sender\", \/\/ Subject line\r\n    text: \"Hello, I'm Roboty, an automatic report sending robot. You will find your files in attachment. I wish you a great day! Bye, Roboty\", \/\/ plaintext body\r\n    html: \"Hello,&lt;br\/&gt;&lt;br\/&gt;I'm Roboty, an automatic report sending robot. You will find your files in attachment.&lt;br\/&gt;&lt;br\/&gt;I wish you a great day!&lt;br\/&gt;&lt;br\/&gt;Bye,&lt;br\/&gt;Roboty\",\r\n    attachments: [\r\n        { filePath: rootFolder + \"graph_1.png\"},\r\n        { filePath: rootFolder + \"graph_2.png\"},\r\n        \/\/add as many as you wish\r\n    ]\r\n}\r\n\r\n\/\/ send mail with defined transport object\r\nsmtpTransport.sendMail(mailOptions, function(error, response){\r\n    if(error){\r\n        console.log(error);\r\n    }else{\r\n        console.log(\"Message sent: \" + response.message);\r\n    }\r\n\r\n    \/\/ if you don't want to use this transport object anymore, uncomment following line\r\n    smtpTransport.close(); \/\/ shut down the connection pool, no more messages\r\n});<\/pre>\n<p>&nbsp;<\/p>\n<h2>Cron jobs<\/h2>\n<p>The following script will run every day at exactly 19:50h. I added the\u00a0PHANTOMJS_EXECUTABLE needed by CasperJS executable, then I wrote the path to CasperJS and the script that we want to execute and finally I redirected all the output to the temporary file for later inspection if needed.<\/p>\n<pre class=\"lang:default decode:true\">50 19 * * * PHANTOMJS_EXECUTABLE=\/home\/app\/bin\/phantomjs \/home\/app\/node\/bin\/casperjs \/home\/app\/casper\/saveImages.js &gt; \/tmp\/outputCheck.txt<\/pre>\n<p>Mailing script runs 5 minutes after the image gathering script and also outputs everything to the temporary file used in some other success status checking script.<\/p>\n<pre class=\"lang:default decode:true\">55\u00a019 * * * \/home\/emtool\/webapps\/node\/bin\/node \/home\/emtool\/my_folder\/casper\/mail.node.js &gt; \/tmp\/emailOut.txt<\/pre>\n<p>Hope this proved useful to someone, and hit me with comments or questions you may have.<\/p>\n<p><a style=\"display: none;\" href=\"http:\/\/www.codeproject.com\" rel=\"tag\">CodeProject<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Why? Recently I had to make a script which runs once per week and gathers images of an admin interface (login required) and sends it to its manager&hellip;<\/p>\n","protected":false},"author":1,"featured_media":189,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8,4],"tags":[],"class_list":["post-187","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-codeproject","category-nodejs"],"_links":{"self":[{"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/posts\/187","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/comments?post=187"}],"version-history":[{"count":13,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/posts\/187\/revisions"}],"predecessor-version":[{"id":2041,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/posts\/187\/revisions\/2041"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/media\/189"}],"wp:attachment":[{"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/media?parent=187"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/categories?post=187"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nikola-breznjak.com\/blog\/wp-json\/wp\/v2\/tags?post=187"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}