Use Markdown to send HTML email via Mutt: now working on iOS mail
A technical configuration post this time around. If you’re a fan of the Mutt command line email program then read on…
For a while I’ve been writing HTML email using Markdown, on the odd occasion I feel the need to format my emails. I’ve followed the instructions on this site and it’s been working to great effect: except in one specific case.
If you also attach a regular file to the email, as well as the HTML output, the text2mime-sendmail.pl script provided stuffs the attachments into the same multipart/alternative
section. Many email clients can figure this out and display the attachments anyway, but crucially it seems that iOS mail can’t, which means that you either only see the attachment, or you only see the HTML without an attachment.
In order to fix this, I rewrote text2mime-sendmail.pl
in Ruby: the original Perl was doing manual text processing, and it seemed to be a good idea to use a proper mail library. I used the Mail library in Ruby to parse the email and send it out with the attachments outside the multipart/alternative
block.
The full issue is described here - I think it’s a bug in iOS Mail rather than anything else.
So, if you’re using the approach referenced above to send HTML email in Mutt, you might want to switch to my script, or modify your scripts to do a similar thing so that your emails are still readable in iOS Mail. Good luck!
Share
More articles
Multiple CI Joes with Rack and Passenger
I’ve recently set up several CI Joe instances to handle our various projects at Eden. We’ve been using Integrity for several months, but it’s caused us a few problems and I yearned for something simpler. CI Joe is about as simple as it gets, and the brevity of the code encourages hacking and customisation.
I’ve now set it up to run multiple Joes using Rack and Passenger for the various different projects we run. Being as I didn’t find much on the net about setting up CI Joe in this way, I thought a fairly detailed howto would be helpful. Let me know how you get on with it.
Folder structure
Our structure looks like this:
Our index file is simply a javascript redirect to our dashboard app, which I mentioned here but will discuss more thoroughly in future posts.
Passenger config
The main Passenger vhost is set up for the cijoe/ directory, and each CI Joe installation has to be symlinked in this way for it to pick them all up.
We put the following file in /etc/httpd/sites.d/ci.conf:
The key bits here are as follows:
- Passenger by default runs ruby processes without a path set, so set the path so CI Joe can call git correctly.
- RackBaseURI is used to start multiple Joe’s, one for each project.
- PassengerMaxInstancesPerApp needs to be set to one, otherwise you’ll get weird results.
- Set your PassengerMaxPoolSize to exactly the number of Joes you’ve got running, so Passenger doesn’t kill the build processes.
- Clear the RAILS_RELATIVE_URL_ROOT environment variable: this will be set by the RackBaseURI calls, and will bleed into your tests, break any that rely on absolute paths.
config.ru
The config.ru we’re using for the individual Joes is as follows:
We keep this in the cijoe-repos/ folder, and symlink it into the different project folders. We also apply a monkey patch to the run_hooks method to strip out backticks: these can stop the hooks running correctly.
Build hooks
If you want to use our build hooks, read on, otherwise you can safely skip the next section.
We have one master build hook script living in cijoe-repos/ which we symlink everywhere. This reads the file structure to find out which project we’re in, and its own symlinked name to work out what’s happened. It then HTTP POSTs the results to our dashboard application:
It’s not very pretty: my bash-fu isn’t up to much. Suggestions for improvement are welcome.
credentials
The credentials file mentioned above is a file which lives in cijoe-repos/. It has one line in it:
These are the user authentication credentials for the POST to your dashboard.
Adding a project
To add a project to the structure:
Then you need to poke the apache vhost configuration to add another RackBaseURI and up the number of processes by 1.
Conclusion
This setup works well for us. We’ve only been running it a few days, but it does feel cleaner and more manageable that the old Integrity system. It’s nice to have each server in seperate processes, with a fully customisable dashboard distinct from the build servers themselves.
With this setup a project could even choose to run a different server: as long as a config.ru file was defined and the HTTP POST notifications are made correctly, it will all work the same way.
I’d love to make it a bit less complex to set up new projects. If you have any ideas for how to improve the setup then do let me know!
Read moreHow I'm testing iPhone apps: part 2
I've recently been doing some iOS development, and working out the best way to test-drive the development of iOS apps was high on my priority list. I know that the automated testing of iOS applications is still not widely practiced and isn't well documented, so I decided to write a series of posts to start to rectify that. You may wish to read part 1 first.
Kiwi
We were looking for a testing framework which supported iOS’s asynchronous programming model and Kiwi answered the call. It has a great syntax, comprehensive set up assistance, asynchronous support and built in mocking. I’d highly recommend you check it out: the syntax helps me to think in the right way and it has pretty much all the features we needed.
Kiwi’s block syntax looks like this:
Much better than the old fashioned xUnit style of testing, in my opinion. You might hate it, of course. You can use Kiwi’s features without having to use the block syntax if you want.
Objective-C’s delegate model
Many of the Apple core libraries use a delegate pattern for handling callbacks from a class. This is similar to Java’s interfaces, and superficially similar to blocks in Ruby and anonymous functions in Javascript.
As an example, let’s take CoreLocation. When wanting to find the location of a phone, you create a new CoreLocationManager
and call startUpdatingLocation
on it:
This call returns immediately: so how do you execute code when the location is found? You use a delegate: an object with responds to the locationManager: didUpdateToLocation: fromLocation
method:
Then you set this object to be the CLLocationManager’s delegate before calling startUpdatingLocation
. Often you set the delegate to self
and define the delegate method on the calling object.
There’s more about this model in this article from Apple.
Testing delegates
This is tricky to test, because we can’t simply do this:
The test will call startUpdatingLocation
, and then immediately check the foundLocation
property to see whether it’s been set. It won’t have been, because the delegate won’t have been called yet.
How were we to stub endpoints such as the location system for for our app? We found two ways of doing this, with varying effectiveness:
- Using Objective-C categories to redefine class methods
- Using a Kiwi stub to inject a derived class which mocks out key methods
Next post, I’ll dive into some detail on both of these methods and show some of the pros and cons of each.
How are you testing iPhone apps? Do chime in throughout the series with suggestions and comments, and I’ll edit the posts as appropriate.
Read moreHow I'm testing iPhone apps: part 1
This week I've been working with Shilling helping them get starting with iOS application development. Part of the deal was for me to learn it myself as we went: I've done hardly any iOS work and we've been learning how to do it together.
As part of this process, working out the best way to test-drive the development of iOS apps was high on my priority list. I know that the automated testing of iOS applications is still not widely practiced and isn't well documented, so I decided to write a series of posts to start to rectify that.
Our goal
There are two main parts to working out how to test-drive applications on a new platform. One is to figure out the testing libraries and write simple 1 + 1 = 2
style tests to prove it can be done. The other half is working out how to apply common testing techniques such as stubbing external systems, isolating tests correctly and optionally driving the interface.
The first of these steps is quite easy on iOS, but the second part is harder. In our case, we have some code which makes use of CoreLocation and the Geonames service to get an iPhone’s location and look up the county name from a latitude and longitude. This means that our code relies on two external services to run, which we want to stub out: we don’t want these services to be called each time our tests run. How were we to set this up correctly?
Apple’s documentation
To kick off our testing adventure on iOS, we started with Apple’s own public documentation on how to test iOS. This is a fairly comprehensive guide on how to set up a project with built in testing, allowing you to write basic SenTest tests quite quickly.
Apple divides its definition of unit testing into two categories:
- Logic tests: these are what I would normally call unit tests. They rely on very few external APIs and are run standalone without the use of a simulator.
- Application tests: these are executed in the context of a running application on a simulator or iOS device.
The document details how to set up both types in your project. There’s a few things missing though:
- They have good ideas about how to write decent tests, but lack information on how to correctly mock system endpoints. I want to do this so that I don’t have to rely on iOS location simulation, or HTTP response data, to make my tests work.
- There was also nothing on how to test asynchronously, which is a real problem as iOS applications are mostly written in this way.
- Application tests are executed in the context of your application, but without extra work it’s not possible to support native UI testing, Capybara style. We are reduced to manipulating controllers directly, which is good enough for now. This assumes you have your user interface wired up correctly. As the app always has to be tested manually anyway then this isn’t too much of a risk, but if you want to take a step further you could use KIF, Frank or Apple’s own UIAutomation. There’s a good post comparing them here.
So we followed through the basic set up instructions, and got a simple test running which added two numbers together. A good start, but useless for real work.
Time to go in search of an asynchronous testing framework: and we found a great one. Next time, I’ll talk about the wonderful Kiwi.
How are you testing iPhone apps? Do chime in throughout the series with suggestions and comments, and I’ll edit the posts as appropriate.
Read more