iPhone Email Attachments – Revisited

iPhone Email Attachments – Revisited

My solution for sending messages via email on the iPhone – detailed here – works for every mail client… except Gmail.

Gmail simply will not let you see embedded images.  Period.

Since this kinda crap really grates on my nerves, I started digging a little deeper.  Plus, I really think there should be a 100% universal way to attach stuff to email messages from the iPhone… and I’m not the only one.  My embedded images solution is workable, but is not wholly satisfying – because it is not a 100% solution.

So, like I usually do when trying to sniff out how a particular piece of web software works without having access to the source, I see what is being sent “over the wire.”  And since I knew that iPhoto on the iPhone WAS able to send an attachment, I sent myself a picture… and then checked the raw message source to see how Apple was doing it.

I sent myself a picture, with no accompanying text, and this is what the “interesting” pieces looked like:

Content-Type: multipart/mixed;
boundary=Apple-Mail-1-782786827
X-Mailer: iPhone Mail (5H11)
Mime-Version: 1.0 (iPhone Mail 5H11)
Date: Wed, 11 Mar 2009 12:13:43 -0400

–Apple-Mail-1-782786827
Content-Type: text/plain;
charset=us-ascii;
format=flowed
Content-Transfer-Encoding: 7bit

–Apple-Mail-1-782786827
Content-Disposition: inline;
filename=photo.jpg
Content-Type: image/jpeg;
name=”photo.jpg”
Content-Transfer-Encoding: base64

Notice the Content-Type of “multipart/mixed.”  No real surprise there… just that when you send a message using the Email client launched by an iPhone application, this is almost always “multipart/alternative”.  First “hmmm.”

Secondly, when I used my methodology of using embeded images (<img src=”data:image/png;base64[my data here in base64]”>), this gets cobbled out as

Content-Type: text/html;
charset=utf-8
Content-Transfer-Encoding: quoted-printable

by the Apple Email Client.  By contrast, Apple creates it’s image attachments by doing the following:

Content-Disposition: inline;
filename=photo.jpg
Content-Type: image/jpeg;
name=”photo.jpg”
Content-Transfer-Encoding: base64

So – why not just do the same thing?

Boundaries.

I don’t know what MIME boundaries (the “Apple-Mail-1-782786827” above) Apple is using to segregate its constituent email pieces (text, html, images, attachments) ahead of time – and they are generated dynamically by the email client when putting together it’s messages.

Bummer.

If I knew what the boundary tag was, I could fake out the client, create my own inline image, and boogey on down.

Now, even though this does seem like a serious roadblock, it may not be a total loss, because it presents both

  • (a) a possible direction to look (fake out a boundary, unlikely though it may be) and
  • (b) it presents another solution path (go down to the socket level and code my own SMTP alternative, so that I can create the MIME code directly to send out my attachments).

(a) looks to be a total non-starter, as it looks like the boundary is made – in part – of a timer component, and there is no way to guess how long someone will keep the message open before sending to reliably fake this out each and every time.  (b) will absolutely work – provided you are motivated to write this dude.  Looks like a commercial opportunity for a Cocoa Touch class, and I may yet do this.

A final and as yet unspoken work around would be to know how Apple preps an image in their email client before sending, so that it’s Mail.app knows to wrap the image up as an inline attachment.  Unfortunately, I don’t know of anywhere I can look to see how they compose their messages (no view source – dang!).

All in all, this has stimulated me to investigate some additional paths for a problem that I thought I had a reasonable solution for – and for many, I do and did.

Onward and upward.

Objective-C and HTTP Basic Authentication

Objective-C and HTTP Basic Authentication

For all the really nice stuff Objective-C lets you do on the iPhone, there are many, many holes left for very common tasks.

One of those tasks is Base64 encoding.

Base64 encoding is used to convert binary data into text that can be transmitted using HTTP (like, say, for embedding images in email) or for somewhat obfuscating user ids and passwords to be sent “in the clear” over HTTP (like for Basic Authentication).

Without much further ado, I present one of a gagillion implementations of Base64 encoding in C:

static char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789"
"+/";

int encode(unsigned s_len, char *src, unsigned d_len, char *dst)
{
unsigned triad;

for (triad = 0; triad < s_len; triad += 3)
{
unsigned long int sr;
unsigned byte;

for (byte = 0; (byte<3)&&(triad+byte<s_len); ++byte)
{
sr <<= 8;
sr |= (*(src+triad+byte) & 0xff);
}

sr <<= (6-((8*byte)%6))%6; /*shift left to next 6bit alignment*/

if (d_len < 4) return 1; /* error - dest too short */

*(dst+0) = *(dst+1) = *(dst+2) = *(dst+3) = '=';
switch(byte)
{
case 3:
*(dst+3) = base64[sr&0x3f];
sr >>= 6;
case 2:
*(dst+2) = base64[sr&0x3f];
sr >>= 6;
case 1:
*(dst+1) = base64[sr&0x3f];
sr >>= 6;
*(dst+0) = base64[sr&0x3f];
}
dst += 4; d_len -= 4;
}

return 0;

}

And here is how one may transmit a user id and password (using NSURLConnection) to establish a connection using Basic Authentication:

myApp.loginString    = (NSMutableString*)[[NSUserDefaults standardUserDefaults] stringForKey:kloginKey];
myApp.passwordString = (NSMutableString*)[[NSUserDefaults standardUserDefaults] stringForKey:kpasswordKey];

NSMutableString *dataStr = (NSMutableString*)[@"" stringByAppendingFormat:@"%@:%@", myApp.loginString, myApp.passwordString];

NSData *encodeData = [dataStr dataUsingEncoding:NSUTF8StringEncoding];
char encodeArray[512];

memset(encodeArray, '\0', sizeof(encodeArray));

// Base64 Encode username and password
encode([encodeData length], (char *)[encodeData bytes], sizeof(encodeArray), encodeArray);

dataStr = [NSString stringWithCString:encodeArray length:strlen(encodeArray)];
myApp.authenticationString = [@"" stringByAppendingFormat:@"Basic %@", dataStr];

// Create asynchronous request
NSMutableURLRequest * theRequest=(NSMutableURLRequest*)[NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://www.somewebdomain.com"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
[theRequest addValue:myApp.authenticationString forHTTPHeaderField:@"Authorization"];

NSURLConnection * theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];

[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
if (theConnection) {
receivedData = [[NSMutableData data] retain];
}
else {
[myApp addTextToLog:@"Could not connect to the network" withCaption:@"MyApp"];
}

Hopefully, this will help people get cracking that were having a hard time getting a handle on the fact that Objective-C is really C – albeit with funky class extensions.

Embedding Images in Outbound Email Using Cocoa Touch

Embedding Images in Outbound Email Using Cocoa Touch

One of the more commonly asked questions about iPhone SDK development is “how do you send attachments in Email using the iPhone SDK?”

The answer is: you can’t.  At least, not yet.

Well, then how are developers seemingly able to do this?  Many of you have seen apps where this looks like this is being done.  The Apple Photos app, for example, seems to be able to do this.

What’s the secret?

Come closer.  You Ready?

Embedded Images.

Embedded images are most commonly seen in your junk email and are a favorite trick used by spammers to circumvent your email filters to slip content in that can’t be scanned textually.

Here, we will use them for good and not evil.  Promise.

Let’s look at some screen grabs and code from my upcoming iPhone App Interpolate.  Interpolate is a numerical analysis app that finds missing range points given a table of data points representing some function, like y=x squared.  In addition to calculating interpolants, it also produces cartesian graphs of each function set, and allows you to send the chart to your friends using email.

img_0012

The code below is from a function call to create my email message.  In my app, I am taking a UIView (or at least, a class derived from UIView) and converting it into a PNG image.  Once I convert the view to PNG, I then convert the image data to a Base64 string, and use that Base64 string as the source for my embedded image in the email.


ChartView *cv = (ChartView *)cvc.view;


UIGraphicsBeginImageContext(cv.bounds.size);
[cv.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();


NSData *imageData = UIImagePNGRepresentation(viewImage);
char encodeArray[64 * 1024];
memset(encodeArray,'', sizeof(encodeArray));

// Exercise for the reader - encode takes the image data buffer and encodes it to base64.

// I can't do everything for you - that spoils the fun.
encode([imageData length], (char *)[imageData bytes], sizeof(encodeArray), encodeArray);


NSString *dataStr = [NSString stringWithCString:encodeArray length:strlen(encodeArray)];


// Save to photo library... maybe another time!
// UIImageWriteToSavedPhotosAlbum(viewImage, self, nil, nil);


NSString *body       = [@"" stringByAppendingFormat:@"<b><img src='data:image/png;base64,%@' alt='Interpolate Chart'></b>", dataStr];
NSString *encoded    = [body stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *title      = [[@"" stringByAppendingFormat:@"Interpolate: Function %@", cvc.title] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString * urlString = [@"" stringByAppendingFormat:@"mailto:me@you.com?subject=%@&body=%@", title, encoded];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlString]];

The really interesting bits are:

  • Converting the UIView to a UIImage using UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
  • Converting the UIImage to NSData using NSData *imageData = UIImagePNGRepresentation(viewImage);
  • Convert the NSData to Base64
  • Converting the Base64 encoded image data into an NSString using NSString *dataStr = [NSString stringWithCString:encodeArray length:strlen(encodeArray)];
  • Embedding the image into email using NSString *body       = [@"" stringByAppendingFormat:@"<b><img src='data:image/png;base64,%@' alt='Interpolate Chart'></b>", dataStr];

IMPORTANT: the <b> and </b> in the embedded image code above must be present, or mail will strip your image.  Don’t ask me why – it just does.

Wait a minute… where is the Base64 encoding mumbo-jumbo done?

Hey – like my old math teacher used to say – the rest is left as an exercise for the reader.

But if you’ve followed along this far, finding a Base64 C routine to use in your own code is the easy part.

Happy Coding.

Simple Formatting in a Cocoa Touch Text Edit Field (UITextField)

Simple Formatting in a Cocoa Touch Text Edit Field (UITextField)

Several challenges of the XCode / Cocoa Touch development environment involve doing things that are trivial in other places, but no so much so within XCode.

One of those challenges is formatting a text edit field.  Social security numbers, phone numbers, postal codes, VINs… the kind of mundane crap that is uber-trivial in tools like MS Access, but often prove to be ball-busting-ly frustrating to do in Objective-C.

For me particularly, I had a price field that I wanted to display.

Apple supplies a couple of keyboard choices for the iPhone that could have done the trick for supplying numeric data entry, but they had about 40 characters more than I needed (0-9, and decimal point were all I really desired, and being lazy, didn’t want to write a regular expression for parsing).

There is a phone number pad (no good) and a number pad (almost what I need – but no decimal point).  But the number pad would be “good enough” if I could just embed an implied decimal point.

Apple has no built in / native way to format a text field with say an embedded decimal (so I wouldn’t have to type it). I had to write my own handler to take care of this.

Here is my home brewed work around for this situation. I’m not going to focus on setting up UITextField events, only on the problem at hand.

Consider the following Edit Changed code:

// Our price changed... we want to format it with an implied decimal point.
-(void)textFieldPriceDidChange:(id)textField {

static BOOL toggle = NO;
if (toggle) {
toggle = NO;
return;
}

NSString* strPrice = [[textField object] text];

strPrice = [strPrice stringByReplacingOccurrencesOfString:@"." withString:@""];
toggle = YES;
price.text = [@"" stringByAppendingFormat:@"%0.2f", [strPrice floatValue]/100.0];

}

The code assumes that I have a UITextField named price somewhere on a form. When the field’s text is changed, the event fires, and I:

-) Strip out any existing decimal point,
-) Divide the float representation of the value by 100, to give an implied 2 decimal point precision,
-) Use the printf-styled %0.2f formatting string to pretty up the output the way I want,
-) Put the value back in the field.

But wait a minute… won’t putting a value back into the price field trigger yet another Edit Change event, and cause an endless loop?

Yes. It will.

But take a look at the BOOL static toggle.

That toggle essentially says “OK. If I see that I am already handling the formatting of this field, reset the toggle, and return.”

This is a simple but very effective way to add formatting to a text edit field, and the concept can easily be extended to other formats without a lot of sweat (%05d-%04d, %3d-%2d-%4d, %2d-%7d, %2d/%2d/%4d – you get the point).

Enjoy… and happy coding.