Using Ruby to Send Targeted Email to an Apple Watch

The other day I ran into a post about sending emails that could fall back to support the limited HTML that the Apple watch can display called hidden Apple Watch email. After reading the post I wondered if I could write a quick example to do what they demonstrated. I turned to Ruby + Ruby mail gem to give this a try and found that there are a few things to know but generally it works well.

To get started make sure you have the mail gem installed:

gem install mail

Next there are two main points to remember before diving into the examples:

  • The sort order of the mime types is important, they need to come in the order listed in the examples or you will end up with the plain text version of the email on the watch
  • You need to include something in the full featured HTML section that can't render on the watch or you will see the full featured HTML on the watch. See the article above for some pointers but generally the watch isn't going to fetch an image from the web so that should do it and is what I have in the following images.

First a simple example that will show plain text for mail clients that don't support HTML at all, normal HTML for full featured clients and a subset of HTML for the Apple watch.

require 'mail'

mail = Mail.new do
  to      'user@something.com'
  from    'person@company.com'
  subject 'Watch mail example'
end

# 
# The order supplied here matters
# 
mail.body.set_sort_order [ "text/plain", "text/watch-html", "text/html" ]

# 
# The order here doesn't matter
# 
text_part = Mail::Part.new do
  body 'This is plain text'
end
mail.text_part = text_part

watch_part = Mail::Part.new do
  content_type 'text/watch-html; charset=UTF-8'
  body '<b>This is HTML for the Apple watch</b>'
end
mail.add_part watch_part

# 
# If this part has something in it that can't display on the watch then 
# the watch part will display. Keep that in mind if you want to force the
# watch part to display. Here the link out to an image will force the 
# fallback to happen.
# 
html_part = Mail::Part.new do
  content_type 'text/html; charset=UTF-8'
  body '<h1>This is HTML</h1><img src="http://images.company.com/someimage.jpg"/>'
end
mail.html_part = html_part

mail.deliver

Here is an example that includes an image that will display on the watch. It is important that in this case the image comes first in the sort order.

require 'mail'

mail = Mail.new do
  to      'user@something.com'
  from    'person@company.com'
  subject 'Watch mail example with image'
end

# 
# The order supplied here matters
# 
mail.body.set_sort_order [ "image/png", "text/plain", "text/watch-html", "text/html" ]

# 
# The order here doesn't matter but you will need to 
# reference the image later.
# 
mail.attachments['test.png'] = File.read('/tmp/test.png')
image_cid = mail.parts.first.url

text_part = Mail::Part.new do
  body 'This is plain text'
end
mail.text_part = text_part

watch_part = Mail::Part.new do
  content_type 'text/watch-html; charset=UTF-8'
  body '<b>This is HTML for the watch</b> <br/> <img src="' + image_cid + '"/>'
end
mail.add_part watch_part

html_part = Mail::Part.new do
  content_type 'text/html; charset=UTF-8'
  body '<h1>This is HTML</h1><img src="http://images.company.com/someimage.jpg"/>'
end
mail.html_part = html_part

mail.deliver

Turn a Raspberry Pi into an iBeacon

Earlier this year Apple added the concept of beacon region monitoring into Core Location. This is more widely known as iBeacon. Right now there isn't a large amount of information on how to take advantage of it outside of iOS and Macs but it is actually pretty easy to implement. The following instructions will get you to a point where a Raspberry Pi can function as an iBeacon (any Linux box should actually work).

Before diving into the technical details I think it is worth noting a few things. There are a few hardware based iBeacons already available in various "beta" states, to name a few: KST's iBeacon, coin for arduino and ReadBearLab's iBeacon. These dedicated devices are going to have a power and most likely a price advantage over the Raspberry Pi so that is something to keep in mind. The setup I used cost around $70 for example and that is around the cost of the KST device but more than the others and the more that are made the more the price will probably decrease. The main advantage of the Raspberry Pi is flexibility and included in that $70 is a wifi dongle that the other devices don't have.

My configuration for this post:

Assuming you have your Pi hardware ready the first step is to install the Raspbian distro. I tested on the 2013-09-25-wheezy-raspbian version. Make sure it boots and then run the following commands as root to get the dependancies ready:

apt-get update
apt-get install libglib2.0-dev libdbus-1-dev libudev-dev libical-dev libreadline6-dev

Next you will need to download and compile a more recent version of Bluez than what is available for the Raspbain distro. I've been able to use a number of versions in the Bluez 5.X family but for this I'll assume Bluez 5.9. Use the following to get it installed and compiled (make sure to do the install part here as root):

wget https://www.kernel.org/pub/linux/bluetooth/bluez-5.9.tar.xz
tar xvJf bluez-5.9.tar.xz
cd bluez-5.9
./configure --disable-systemd --enable-library
make
make install

Now you have Bluez installed with bluetooth library support. There are also a number of tools available at this point. The first one you want to run is hciconfig to configure your bluetooth device. It works a lot like ifconfig if you are familiar with setting up network interface. If you run it without any command line arguments you will get a list of bluetooth devices:

hciconfig

# hci0:   Type: BR/EDR  Bus: USB
#         BD Address: 00:02:72:32:CA:23  ACL MTU: 1021:8  SCO MTU: 64:1
#         DOWN
#         RX bytes:340 acl:0 sco:0 events:7 errors:0
#         TX bytes:54 acl:0 sco:0 commands:12 errors:0

You want to bring the bluetooth device up so it is available:

hciconfig hci0 up
hciconfig

# hci0:   Type: BR/EDR  Bus: USB
#         BD Address: 00:02:72:32:CA:23  ACL MTU: 1021:8  SCO MTU: 64:1
#         UP RUNNING
#         RX bytes:813 acl:0 sco:0 events:26 errors:0
#         TX bytes:374 acl:0 sco:0 commands:31 errors:0

Make sure you see "UP RUNNING" before proceeding. You will probably want to add the command to bring the bluetooth device up to the startup script. Next you will want to grab my bluez-ibeacon repo from github and build it:

git clone https://github.com/carsonmcdonald/bluez-ibeacon.git
bluez-ibeacon/bluez-beacon/
make

Now you have a binary named ibeacon that you can run and that will turn the Pi into an iBeacon:

./ibeacon 200 e2c56db5dffb48d2b060d0f5a71096e0 1 1 -29

You can read more about what the above means in the README for the bluez-ibeacon project.

There is a demo iOS app in the same bluez-ibeacon project that you can use to then detect the beacon now that it is running.

Bluetooth 4.0 LE on Raspberry Pi with Bluez 5.x

Over the holiday I had a little time to fiddle with the Raspberry Pi I got earlier in the summer and I started wondering how hard it would be to get a Bluetooth LE adapter working. It turned out not to be as hard to get working as I thought it might be thanks to recently added support in the Bluez 5.x Bluetooth stack. What follows is the information you need to get things going.

To start with I picked the IOGEAR Bluetooth 4.0 USB Micro Adapter (GBU521) that can be found on Amazon for just $13 since it looked like the chip it uses is decently supported with recent Linux kernels. The only issue I had is the size itself, if it didn't have a little nub on the end it would be too small to pull back out of the USB plug.

Continue reading

Direct Browser Uploading – Amazon S3, CORS, FileAPI, XHR2 and Signed PUTs

I've been hacking around with FileAPI and XHR2 in HTML5 recently (more on why hopefully in another month or so). So when Amazon announced S3 CORS support I figured I should create a demo of directly uploading a file to S3 from a browser.

The first thing to understand is that while the upload happens directly to S3 there still needs to be some server side code that signs the URL used by the PUT call. That bit of code is really simple and I'm including an example at the end for both PHP and Ruby. If you want to skip to the fun part you can check out the PHP and Ruby example code on github (instructions there on deploying to Heroku as well).

Second there are a good number of technologies involved here so I've compiled a list of helpful links in case you aren't already familiar with them and/or want a reference:

Continue reading

Embed Ruby in Your iOS Apps Using mruby

I've been playing with mruby for the past week or so. If you haven't seen it yet it is an embeddable version of Ruby. The first thing I wonder about when I heard about mruby last year a RubyConf was embedding it in iOS apps. Now that the initial version has been released I figured I would give it a try.

There are a few things to take into account before diving into this. The first is that the mruby project is very new and there are a number of gaps in the language support right now but the goal is to support the ISO definition of Ruby at some point. The second thing to know is that I'm talking about embedding Ruby here and not writing iOS apps using Ruby. I'm more interested in the potential of Ruby as a scripting language for something like a game. If you want to look into writing iOS apps using Ruby check out RubyMotion or the MobiRuby project (MobiRuby is based on mruby).

Continue reading

Segmenting WebM Video and the MediaSource API

For a while now I've seen people ask when support for Apple's Pantos HTTP live streaming would make it past Safari and iOS. The answer seems to have been that it wasn't clear that Pantos streaming was the best option and something else would come about eventually that would be more flexible. There have been other options but they involve either Flash or Silverlight and most people want something that works with html5 video. After a long wait it seems like the time is getting close now with the MediaSource API.

The MediaSource API has experimental support in Chrome and can be enabled by using the chrome://flags option. To see it in action you can go to the MediaSource demo page. You can also read a litte more about it here although the spec linked to above is probably a better place to learn about it.

A while ago I created a tool for segmenting H264 video in a Pantos compliant way. When I saw the MediaSource API I wondered how the same type of tool might fit in. The first thing to note is that the Pantos draft describes a complete technique for video streaming while the MediaSource API gives you the tools to stream video and leaves the technique. What follows is a simple technique for segmenting a WebM video in a way that allows standard streaming with the MediaSource API in the same fasion as the Pantos draft technique. While this example will not support variable rate streams it could be expanded to do so and would be the next logical step.

Continue reading

Range Requests with Ajax

I ran across something the other day that made wonder about doing range requests using ajax. For some reason it wasn't obvious at first if this would be easy but as it turns out it is.

If you aren't familiar with range requests head over to the HTTP RFC and check out the range header. Your web server needs to support range requests for this to be useful but most do so that shouldn't be a huge issue. As a bonus you will find that some CDNs support range request as well (Amazon S3 for example).

Continue reading

Using WebP to Reduce Native iOS App Size

Last year Google released WebM as an alternative to h264 encoded video. They followed that up with the release of WebP as an alternative to JPG. Ever since the release I've been thinking about giving it a try on iOS to see how well it might work to reduce application size. As a bonus to reduced size, WebP also supports an alpha channel that JPG doesn't (there is more information available on the original release blog post).

Continue reading

Using the Google Closure Compiler in Java

I recently had a chance to try out Google's closure compiler. The closure compiler is similar to the YUI compressor except that along with minimizing it may rewrite the JavaScript. If you want to understand more about what it does start at the overview documentation and then go from there.

What I needed was a way to use the closure compiler in an Ant task. The Ant task that comes with the library is good but there wasn't a way for me to integrate it into an existing system that wasn't going to change. After looking around for some example code and not finding any I went into the library's Ant task and figured out how to wire it all up myself.

Continue reading

Google Analytics Dashboard WordPress Plugin Version 2.0 Released

It has taken me a while but I've finally been able to release version 2 of the Google Analytics Dashboard WordPress Plugin. The primary enhancement of this version is that it no longer blocks the dashboard, posts or pages interfaces while loading. The next major change is an upgrade to using Google's OAuth login system (see my Google OAuth example using PHP for more information on how I did that if you are interested). The old login system is still available but the OAuth login is the one to use going forward and I may remove the old one at some point. The move to OAuth along with the refactoring I did to the code will allow support for other Google sites such as Feedburner. As a bonus I also moved the caching system to the newer WordPress transient storage interface. The use of the transient storage interface should fix one of the biggest issues people have seen in the past so no more worrying about finding a temp directory that is writable.

Here are a list of the major changes:

  • The dashboard panel now loads asynchronously so the entire dashboard doesn't block while it is loading
  • Made the analytics column in posts and pages load asynchronously so that it doesn't block the loading of the page
  • Added support for Google OAuth logins
  • Use transient API support with wordpress version 2.8+
  • Added ability to support multiple analytics sources

Some other minor changes:

  • Stop unlink warnings when caching won't work
  • Refactored code so that major parts are split into classes
  • Refactored code to better seperate UI code
  • Fixed mime type not being sent correctly for admin area javascript file
  • Fix bug in wordpress version checking