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.
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.