steps:
– At first add CFNetwork framework to your project framework.
– add the followig .h and .m file to your project classes
1. Base64Transcoder.h
#include <UIKit/UIKit.h>
extern size_t EstimateBas64EncodedDataSize(size_t inDataSize);
extern size_t EstimateBas64DecodedDataSize(size_t inDataSize);
extern bool Base64EncodeData(const void *inInputData, size_t inInputDataSize, char *outOutputData, size_t *ioOutputDataSize);
extern bool Base64DecodeData(const void *inInputData, size_t inInputDataSize, void *ioOutputData, size_t *ioOutputDataSize);
2. Base64Transcoder.m
#include “Base64Transcoder.h”
#include <math.h>
const UInt8 kBase64EncodeTable[64] = {
/*  0 */ ‘A’,    /*  1 */ ‘B’,    /*  2 */ ‘C’,    /*  3 */ ‘D’,
/*  4 */ ‘E’,    /*  5 */ ‘F’,    /*  6 */ ‘G’,    /*  7 */ ‘H’,
/*  8 */ ‘I’,    /*  9 */ ‘J’,    /* 10 */ ‘K’,    /* 11 */ ‘L’,
/* 12 */ ‘M’,    /* 13 */ ‘N’,    /* 14 */ ‘O’,    /* 15 */ ‘P’,
/* 16 */ ‘Q’,    /* 17 */ ‘R’,    /* 18 */ ‘S’,    /* 19 */ ‘T’,
/* 20 */ ‘U’,    /* 21 */ ‘V’,    /* 22 */ ‘W’,    /* 23 */ ‘X’,
/* 24 */ ‘Y’,    /* 25 */ ‘Z’,    /* 26 */ ‘a’,    /* 27 */ ‘b’,
/* 28 */ ‘c’,    /* 29 */ ‘d’,    /* 30 */ ‘e’,    /* 31 */ ‘f’,
/* 32 */ ‘g’,    /* 33 */ ‘h’,    /* 34 */ ‘i’,    /* 35 */ ‘j’,
/* 36 */ ‘k’,    /* 37 */ ‘l’,    /* 38 */ ‘m’,    /* 39 */ ‘n’,
/* 40 */ ‘o’,    /* 41 */ ‘p’,    /* 42 */ ‘q’,    /* 43 */ ‘r’,
/* 44 */ ‘s’,    /* 45 */ ‘t’,    /* 46 */ ‘u’,    /* 47 */ ‘v’,
/* 48 */ ‘w’,    /* 49 */ ‘x’,    /* 50 */ ‘y’,    /* 51 */ ‘z’,
/* 52 */ ‘0’,    /* 53 */ ‘1’,    /* 54 */ ‘2’,    /* 55 */ ‘3’,
/* 56 */ ‘4’,    /* 57 */ ‘5’,    /* 58 */ ‘6’,    /* 59 */ ‘7’,
/* 60 */ ‘8’,    /* 61 */ ‘9’,    /* 62 */ ‘+’,    /* 63 */ ‘/’
};
/*
-1 = Base64 end of data marker.
-2 = White space (tabs, cr, lf, space)
-3 = Noise (all non whitespace, non-base64 characters)
-4 = Dangerous noise
-5 = Illegal noise (null byte)
*/
const SInt8 kBase64DecodeTable[128] = {
/* 0x00 */ -5,     /* 0x01 */ -3,     /* 0x02 */ -3,     /* 0x03 */ -3,
/* 0x04 */ -3,     /* 0x05 */ -3,     /* 0x06 */ -3,     /* 0x07 */ -3,
/* 0x08 */ -3,     /* 0x09 */ -2,     /* 0x0a */ -2,     /* 0x0b */ -2,
/* 0x0c */ -2,     /* 0x0d */ -2,     /* 0x0e */ -3,     /* 0x0f */ -3,
/* 0x10 */ -3,     /* 0x11 */ -3,     /* 0x12 */ -3,     /* 0x13 */ -3,
/* 0x14 */ -3,     /* 0x15 */ -3,     /* 0x16 */ -3,     /* 0x17 */ -3,
/* 0x18 */ -3,     /* 0x19 */ -3,     /* 0x1a */ -3,     /* 0x1b */ -3,
/* 0x1c */ -3,     /* 0x1d */ -3,     /* 0x1e */ -3,     /* 0x1f */ -3,
/* ‘ ‘ */ -2,    /* ‘!’ */ -3,    /* ‘”‘ */ -3,    /* ‘#’ */ -3,
/* ‘$’ */ -3,    /* ‘%’ */ -3,    /* ‘&’ */ -3,    /* ”’ */ -3,
/* ‘(‘ */ -3,    /* ‘)’ */ -3,    /* ‘*’ */ -3,    /* ‘+’ */ 62,
/* ‘,’ */ -3,    /* ‘-‘ */ -3,    /* ‘.’ */ -3,    /* ‘/’ */ 63,
/* ‘0’ */ 52,    /* ‘1’ */ 53,    /* ‘2’ */ 54,    /* ‘3’ */ 55,
/* ‘4’ */ 56,    /* ‘5’ */ 57,    /* ‘6’ */ 58,    /* ‘7’ */ 59,
/* ‘8’ */ 60,    /* ‘9’ */ 61,    /* ‘:’ */ -3,    /* ‘;’ */ -3,
/* ‘<‘ */ -3,    /* ‘=’ */ -1,    /* ‘>’ */ -3,    /* ‘?’ */ -3,
/* ‘@’ */ -3,    /* ‘A’ */ 0,    /* ‘B’ */  1,    /* ‘C’ */  2,
/* ‘D’ */  3,    /* ‘E’ */  4,    /* ‘F’ */  5,    /* ‘G’ */  6,
/* ‘H’ */  7,    /* ‘I’ */  8,    /* ‘J’ */  9,    /* ‘K’ */ 10,
/* ‘L’ */ 11,    /* ‘M’ */ 12,    /* ‘N’ */ 13,    /* ‘O’ */ 14,
/* ‘P’ */ 15,    /* ‘Q’ */ 16,    /* ‘R’ */ 17,    /* ‘S’ */ 18,
/* ‘T’ */ 19,    /* ‘U’ */ 20,    /* ‘V’ */ 21,    /* ‘W’ */ 22,
/* ‘X’ */ 23,    /* ‘Y’ */ 24,    /* ‘Z’ */ 25,    /* ‘[‘ */ -3,
/* ‘\’ */ -3,    /* ‘]’ */ -3,    /* ‘^’ */ -3,    /* ‘_’ */ -3,
/* ‘`’ */ -3,    /* ‘a’ */ 26,    /* ‘b’ */ 27,    /* ‘c’ */ 28,
/* ‘d’ */ 29,    /* ‘e’ */ 30,    /* ‘f’ */ 31,    /* ‘g’ */ 32,
/* ‘h’ */ 33,    /* ‘i’ */ 34,    /* ‘j’ */ 35,    /* ‘k’ */ 36,
/* ‘l’ */ 37,    /* ‘m’ */ 38,    /* ‘n’ */ 39,    /* ‘o’ */ 40,
/* ‘p’ */ 41,    /* ‘q’ */ 42,    /* ‘r’ */ 43,    /* ‘s’ */ 44,
/* ‘t’ */ 45,    /* ‘u’ */ 46,    /* ‘v’ */ 47,    /* ‘w’ */ 48,
/* ‘x’ */ 49,    /* ‘y’ */ 50,    /* ‘z’ */ 51,    /* ‘{‘ */ -3,
/* ‘|’ */ -3,    /* ‘}’ */ -3,    /* ‘~’ */ -3,    /* 0x7f */ -3
};
const UInt8 kBits_00000011 = 0x03;
const UInt8 kBits_00001111 = 0x0F;
const UInt8 kBits_00110000 = 0x30;
const UInt8 kBits_00111100 = 0x3C;
const UInt8 kBits_00111111 = 0x3F;
const UInt8 kBits_11000000 = 0xC0;
const UInt8 kBits_11110000 = 0xF0;
const UInt8 kBits_11111100 = 0xFC;
size_t EstimateBas64EncodedDataSize(size_t inDataSize)
{
size_t theEncodedDataSize = (int)ceil(inDataSize / 3.0) * 4;
theEncodedDataSize = theEncodedDataSize / 72 * 74 + theEncodedDataSize % 72;
return(theEncodedDataSize);
}
size_t EstimateBas64DecodedDataSize(size_t inDataSize)
{
size_t theDecodedDataSize = (int)ceil(inDataSize / 4.0) * 3;
//theDecodedDataSize = theDecodedDataSize / 72 * 74 + theDecodedDataSize % 72;
return(theDecodedDataSize);
}
bool Base64EncodeData(const void *inInputData, size_t inInputDataSize, char *outOutputData, size_t *ioOutputDataSize)
{
size_t theEncodedDataSize = EstimateBas64EncodedDataSize(inInputDataSize);
if (*ioOutputDataSize < theEncodedDataSize)
return(false);
*ioOutputDataSize = theEncodedDataSize;
const UInt8 *theInPtr = (const UInt8 *)inInputData;
UInt32 theInIndex = 0, theOutIndex = 0;
for (; theInIndex < (inInputDataSize / 3) * 3; theInIndex += 3)
{
outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_11111100) >> 2];
outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_00000011) << 4 | (theInPtr[theInIndex + 1] & kBits_11110000) >> 4];
outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex + 1] & kBits_00001111) << 2 | (theInPtr[theInIndex + 2] & kBits_11000000) >> 6];
outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex + 2] & kBits_00111111) >> 0];
//    if (theOutIndex % 74 == 72)
//        {
//        outOutputData[theOutIndex++] = ‘\r’;
//        outOutputData[theOutIndex++] = ‘\n’;
//        }
}
const size_t theRemainingBytes = inInputDataSize – theInIndex;
if (theRemainingBytes == 1)
{
outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_11111100) >> 2];
outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_00000011) << 4 | (0 & kBits_11110000) >> 4];
outOutputData[theOutIndex++] = ‘=’;
outOutputData[theOutIndex++] = ‘=’;
//    if (theOutIndex % 74 == 72)
//        {
//        outOutputData[theOutIndex++] = ‘\r’;
//        outOutputData[theOutIndex++] = ‘\n’;
//        }
}
else if (theRemainingBytes == 2)
{
outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_11111100) >> 2];
outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_00000011) << 4 | (theInPtr[theInIndex + 1] & kBits_11110000) >> 4];
outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex + 1] & kBits_00001111) << 2 | (0 & kBits_11000000) >> 6];
outOutputData[theOutIndex++] = ‘=’;
//    if (theOutIndex % 74 == 72)
//        {
//        outOutputData[theOutIndex++] = ‘\r’;
//        outOutputData[theOutIndex++] = ‘\n’;
//        }
}
return(true);
}
bool Base64DecodeData(const void *inInputData, size_t inInputDataSize, void *ioOutputData, size_t *ioOutputDataSize)
{
memset(ioOutputData, ‘.’, *ioOutputDataSize);
size_t theDecodedDataSize = EstimateBas64DecodedDataSize(inInputDataSize);
if (*ioOutputDataSize < theDecodedDataSize)
return(false);
*ioOutputDataSize = 0;
const UInt8 *theInPtr = (const UInt8 *)inInputData;
UInt8 *theOutPtr = (UInt8 *)ioOutputData;
size_t theInIndex = 0, theOutIndex = 0;
UInt8 theOutputOctet;
size_t theSequence = 0;
for (; theInIndex < inInputDataSize; )
{
SInt8 theSextet = 0;
SInt8 theCurrentInputOctet = theInPtr[theInIndex];
theSextet = kBase64DecodeTable[theCurrentInputOctet];
if (theSextet == -1)
break;
while (theSextet == -2)
{
theCurrentInputOctet = theInPtr[++theInIndex];
theSextet = kBase64DecodeTable[theCurrentInputOctet];
}
while (theSextet == -3)
{
theCurrentInputOctet = theInPtr[++theInIndex];
theSextet = kBase64DecodeTable[theCurrentInputOctet];
}
if (theSequence == 0)
{
theOutputOctet = (theSextet >= 0 ? theSextet : 0) << 2 & kBits_11111100;
}
else if (theSequence == 1)
{
theOutputOctet |= (theSextet >- 0 ? theSextet : 0) >> 4 & kBits_00000011;
theOutPtr[theOutIndex++] = theOutputOctet;
}
else if (theSequence == 2)
{
theOutputOctet = (theSextet >= 0 ? theSextet : 0) << 4 & kBits_11110000;
}
else if (theSequence == 3)
{
theOutputOctet |= (theSextet >= 0 ? theSextet : 0) >> 2 & kBits_00001111;
theOutPtr[theOutIndex++] = theOutputOctet;
}
else if (theSequence == 4)
{
theOutputOctet = (theSextet >= 0 ? theSextet : 0) << 6 & kBits_11000000;
}
else if (theSequence == 5)
{
theOutputOctet |= (theSextet >= 0 ? theSextet : 0) >> 0 & kBits_00111111;
theOutPtr[theOutIndex++] = theOutputOctet;
}
theSequence = (theSequence + 1) % 6;
if (theSequence != 2 && theSequence != 4)
theInIndex++;
}
*ioOutputDataSize = theOutIndex;
return(true);
}
3. HSK_CFUtilities.h
#import <Foundation/Foundation.h>
#import <CFNetwork/CFNetwork.h>
void CFStreamCreatePairWithUNIXSocketPair(CFAllocatorRef alloc, CFReadStreamRef *readStream, CFWriteStreamRef *writeStream);
CFIndex CFWriteStreamWriteFully(CFWriteStreamRef outputStream, const uint8_t* buffer, CFIndex length);
4. HSK_CFUtilities.m
#include “HSK_CFUtilities.h”
#include <sys/types.h>
#include <sys/socket.h>
void CFStreamCreatePairWithUNIXSocketPair(CFAllocatorRef alloc, CFReadStreamRef *readStream, CFWriteStreamRef *writeStream)
{
int sockpair[2];
int success = socketpair(AF_UNIX, SOCK_STREAM, 0, sockpair);
if (success < 0)
{
[NSException raise:@”HSK_CFUtilitiesErrorDomain” format:@”Unable to create socket pair, errno: %d”, errno];
}
CFStreamCreatePairWithSocket(NULL, sockpair[0], readStream, NULL);
CFReadStreamSetProperty(*readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
CFStreamCreatePairWithSocket(NULL, sockpair[1], NULL, writeStream);
CFWriteStreamSetProperty(*writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
}
CFIndex CFWriteStreamWriteFully(CFWriteStreamRef outputStream, const uint8_t* buffer, CFIndex length)
{
CFIndex bufferOffset = 0;
CFIndex bytesWritten;
while (bufferOffset < length)
{
if (CFWriteStreamCanAcceptBytes(outputStream))
{
bytesWritten = CFWriteStreamWrite(outputStream, &(buffer[bufferOffset]), length – bufferOffset);
if (bytesWritten < 0)
{
// Bail!
return bytesWritten;
}
bufferOffset += bytesWritten;
}
else if (CFWriteStreamGetStatus(outputStream) == kCFStreamStatusError)
{
[NSException raise:@”HSK_CFUtilitiesErrorDomain” format:@”Error writing bytes to stream!”];
}
else
{
// Pump the runloop
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.0, true);
}
}
return bufferOffset;
}
5. NSData+Base64Additions.h
#import <UIKit/UIKit.h>
@interface NSData (Base64Additions)
+(id)decodeBase64ForString:(NSString *)decodeString;
+(id)decodeWebSafeBase64ForString:(NSString *)decodeString;
-(NSString *)encodeBase64ForData;
-(NSString *)encodeWebSafeBase64ForData;
@end
6. NSData+Base64Additions.m
#import “NSData+Base64Additions.h”
#import “Base64Transcoder.h”
@implementation NSData (Base64Additions)
+(id)decodeBase64ForString:(NSString *)decodeString
{
NSData *decodeBuffer = nil;
// Must be 7-bit clean!
NSData *tmpData = [decodeString dataUsingEncoding:NSASCIIStringEncoding];
size_t estSize = EstimateBas64DecodedDataSize([tmpData length]);
uint8_t* outBuffer = calloc(estSize, sizeof(uint8_t));
size_t outBufferLength = estSize;
if (Base64DecodeData([tmpData bytes], [tmpData length], outBuffer, &outBufferLength))
{
decodeBuffer = [NSData dataWithBytesNoCopy:outBuffer length:outBufferLength freeWhenDone:YES];
}
else
{
free(outBuffer);
[NSException raise:@”NSData+Base64AdditionsException” format:@”Unable to decode data!”];
}
return decodeBuffer;
}
+(id)decodeWebSafeBase64ForString:(NSString *)decodeString
{
return [NSData decodeBase64ForString:[[decodeString stringByReplacingOccurrencesOfString:@”-” withString:@”+”] stringByReplacingOccurrencesOfString:@”_” withString:@”/”]];
}
-(NSString *)encodeBase64ForData
{
NSString *encodedString = nil;
// Make sure this is nul-terminated.
size_t outBufferEstLength = EstimateBas64EncodedDataSize([self length]) + 1;
char *outBuffer = calloc(outBufferEstLength, sizeof(char));
size_t outBufferLength = outBufferEstLength;
if (Base64EncodeData([self bytes], [self length], outBuffer, &outBufferLength))
{
encodedString = [NSString stringWithCString:outBuffer encoding:NSASCIIStringEncoding];
}
else
{
[NSException raise:@”NSData+Base64AdditionsException” format:@”Unable to encode data!”];
}
free(outBuffer);
return encodedString;
}
-(NSString *)encodeWebSafeBase64ForData
{
return [[[self encodeBase64ForData] stringByReplacingOccurrencesOfString:@”+” withString:@”-“] stringByReplacingOccurrencesOfString:@”/” withString:@”_”];
}
@end
7. NSStream+SKPSMTPExtensions.h
#import <UIKit/UIKit.h>
#import <CFNetwork/CFNetwork.h>
@interface NSStream (SKPSMTPExtensions)
+ (void)getStreamsToHostNamed:(NSString *)hostName port:(NSInteger)port inputStream:(NSInputStream **)inputStream outputStream:(NSOutputStream **)outputStream;
@end
8. NSStream+SKPSMTPExtensions.m
#import “NSStream+SKPSMTPExtensions.h”
@implementation NSStream (SKPSMTPExtensions)
+ (void)getStreamsToHostNamed:(NSString *)hostName port:(NSInteger)port inputStream:(NSInputStream **)inputStream outputStream:(NSOutputStream **)outputStream
{
CFHostRef           host;
CFReadStreamRef     readStream;
CFWriteStreamRef    writeStream;
readStream = NULL;
writeStream = NULL;
host = CFHostCreateWithName(NULL, (CFStringRef) hostName);
if (host != NULL)
{
(void) CFStreamCreatePairWithSocketToCFHost(NULL, host, port, &readStream, &writeStream);
CFRelease(host);
}
if (inputStream == NULL)
{
if (readStream != NULL)
{
CFRelease(readStream);
}
}
else
{
*inputStream = [(NSInputStream *) readStream autorelease];
}
if (outputStream == NULL)
{
if (writeStream != NULL)
{
CFRelease(writeStream);
}
}
else
{
*outputStream = [(NSOutputStream *) writeStream autorelease];
}
}
@end
9. SKPSMTPMessage.h
#import <UIKit/UIKit.h>
#import <CFNetwork/CFNetwork.h>
enum
{
kSKPSMTPIdle = 0,
kSKPSMTPConnecting,
kSKPSMTPWaitingEHLOReply,
kSKPSMTPWaitingTLSReply,
kSKPSMTPWaitingLOGINUsernameReply,
kSKPSMTPWaitingLOGINPasswordReply,
kSKPSMTPWaitingAuthSuccess,
kSKPSMTPWaitingFromReply,
kSKPSMTPWaitingToReply,
kSKPSMTPWaitingForEnterMail,
kSKPSMTPWaitingSendSuccess,
kSKPSMTPWaitingQuitReply,
kSKPSMTPMessageSent
};
typedef NSUInteger SKPSMTPState;
// Message part keys
extern NSString *kSKPSMTPPartContentDispositionKey;
extern NSString *kSKPSMTPPartContentTypeKey;
extern NSString *kSKPSMTPPartMessageKey;
extern NSString *kSKPSMTPPartContentTransferEncodingKey;
// Error message codes
#define kSKPSMPTErrorConnectionTimeout -5
#define kSKPSMTPErrorConnectionFailed -3
#define kSKPSMTPErrorConnectionInterrupted -4
#define kSKPSMTPErrorUnsupportedLogin -2
#define kSKPSMTPErrorTLSFail -1
#define kSKPSMTPErrorInvalidUserPass 535
#define kSKPSMTPErrorInvalidMessage 550
#define kSKPSMTPErrorNoRelay 530
@class SKPSMTPMessage;
@protocol SKPSMTPMessageDelegate
@required
-(void)messageSent:(SKPSMTPMessage *)message;
-(void)messageFailed:(SKPSMTPMessage *)message error:(NSError *)error;
@end
@interface SKPSMTPMessage : NSObject
{
NSString *login;
NSString *pass;
NSString *relayHost;
NSArray *relayPorts;
NSString *subject;
NSString *fromEmail;
NSString *toEmail;
NSString *ccEmail;
NSArray *parts;
NSOutputStream *outputStream;
NSInputStream *inputStream;
BOOL requiresAuth;
BOOL wantsSecure;
BOOL validateSSLChain;
SKPSMTPState sendState;
BOOL isSecure;
NSMutableString *inputString;
// Auth support flags
BOOL serverAuthCRAMMD5;
BOOL serverAuthPLAIN;
BOOL serverAuthLOGIN;
BOOL serverAuthDIGESTMD5;
// Content support flags
BOOL server8bitMessages;
id <SKPSMTPMessageDelegate> delegate;
NSTimeInterval connectTimeout;
NSTimer *connectTimer;
NSTimer *watchdogTimer;
}
@property(nonatomic, retain) NSString *login;
@property(nonatomic, retain) NSString *pass;
@property(nonatomic, retain) NSString *relayHost;
@property(nonatomic, retain) NSArray *relayPorts;
@property(nonatomic, assign) BOOL requiresAuth;
@property(nonatomic, assign) BOOL wantsSecure;
@property(nonatomic, assign) BOOL validateSSLChain;
@property(nonatomic, retain) NSString *subject;
@property(nonatomic, retain) NSString *fromEmail;
@property(nonatomic, retain) NSString *toEmail;
@property(nonatomic, retain) NSString *ccEmail;
@property(nonatomic, retain) NSArray *parts;
@property(nonatomic, assign) NSTimeInterval connectTimeout;
@property(nonatomic, assign) id <SKPSMTPMessageDelegate> delegate;
– (BOOL)send;
@end
10. SKPSMTPMessage.m
#import “SKPSMTPMessage.h”
#import “NSData+Base64Additions.h”
#import “NSStream+SKPSMTPExtensions.h”
#import “HSK_CFUtilities.h”
NSString *kSKPSMTPPartContentDispositionKey = @”kSKPSMTPPartContentDispositionKey”;
NSString *kSKPSMTPPartContentTypeKey = @”kSKPSMTPPartContentTypeKey”;
NSString *kSKPSMTPPartMessageKey = @”kSKPSMTPPartMessageKey”;
NSString *kSKPSMTPPartContentTransferEncodingKey = @”kSKPSMTPPartContentTransferEncodingKey”;
#define SHORT_LIVENESS_TIMEOUT 20.0
#define LONG_LIVENESS_TIMEOUT 60.0
@interface SKPSMTPMessage ()
@property(nonatomic, retain) NSMutableString *inputString;
@property(nonatomic, retain) NSTimer *connectTimer;
@property(nonatomic, retain) NSTimer *watchdogTimer;
– (void)parseBuffer;
– (void)sendParts;
– (void)cleanUpStreams;
– (void)startShortWatchdog;
– (void)stopWatchdog;
– (NSString *)formatAnAddress:(NSString *)address;
– (NSString *)formatAddresses:(NSString *)addresses;
@end
@implementation SKPSMTPMessage
@synthesize login, pass, relayHost, relayPorts, subject, fromEmail, toEmail, ccEmail, parts, requiresAuth, inputString, wantsSecure, \
delegate, connectTimer, connectTimeout, watchdogTimer, validateSSLChain;
– (id)init
{
static NSArray *defaultPorts = nil;
if (!defaultPorts)
{
defaultPorts = [[NSArray alloc] initWithObjects:[NSNumber numberWithShort:25], [NSNumber numberWithShort:465], [NSNumber numberWithShort:587], nil];
}
if (self = [super init])
{
// Setup the default ports
self.relayPorts = defaultPorts;
// setup a default timeout (8 seconds)
connectTimeout = 8.0;
// by default, validate the SSL chain
validateSSLChain = YES;
}
return self;
}
– (void)dealloc
{
self.login = nil;
self.pass = nil;
self.relayHost = nil;
self.relayPorts = nil;
self.subject = nil;
self.fromEmail = nil;
self.toEmail = nil;
self.ccEmail = nil;
self.parts = nil;
self.inputString = nil;
[inputStream release];
inputStream = nil;
[outputStream release];
outputStream = nil;
[self.connectTimer invalidate];
self.connectTimer = nil;
[self stopWatchdog];
[super dealloc];
}
– (void)startShortWatchdog
{
self.watchdogTimer = [NSTimer scheduledTimerWithTimeInterval:SHORT_LIVENESS_TIMEOUT target:self selector:@selector(connectionWatchdog:) userInfo:nil repeats:NO];
}
– (void)startLongWatchdog
{
self.watchdogTimer = [NSTimer scheduledTimerWithTimeInterval:LONG_LIVENESS_TIMEOUT target:self selector:@selector(connectionWatchdog:) userInfo:nil repeats:NO];
}
– (void)stopWatchdog
{
[self.watchdogTimer invalidate];
self.watchdogTimer = nil;
}
– (BOOL)send
{
NSAssert(sendState == kSKPSMTPIdle, @”Message has already been sent!”);
if (requiresAuth)
{
NSAssert(login, @”auth requires login”);
NSAssert(pass, @”auth requires pass”);
}
NSAssert(relayHost, @”send requires relayHost”);
NSAssert(subject, @”send requires subject”);
NSAssert(fromEmail, @”send requires fromEmail”);
NSAssert(toEmail, @”send requires toEmail”);
NSAssert(parts, @”send requires parts”);
if (![relayPorts count])
{
[delegate messageFailed:self
error:[NSError errorWithDomain:@”SKPSMTPMessageError”
code:kSKPSMTPErrorConnectionFailed
userInfo:[NSDictionary dictionaryWithObject:@”unable to connect to server”
forKey:NSLocalizedDescriptionKey]]];
return NO;
}
// Grab the next relay port
short relayPort = [[relayPorts objectAtIndex:0] shortValue];
// Pop this off the head of the queue.
self.relayPorts = ([relayPorts count] > 1) ? [relayPorts subarrayWithRange:NSMakeRange(1, [relayPorts count] – 1)] : [NSArray array];
self.connectTimer = [NSTimer scheduledTimerWithTimeInterval:connectTimeout
target:self
selector:@selector(connectionConnectedCheck:)
userInfo:nil
repeats:NO];
[NSStream getStreamsToHostNamed:relayHost port:relayPort inputStream:&inputStream outputStream:&outputStream];
if ((inputStream != nil) && (outputStream != nil))
{
sendState = kSKPSMTPConnecting;
isSecure = NO;
[inputStream retain];
[outputStream retain];
[inputStream setDelegate:self];
[outputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSRunLoopCommonModes];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSRunLoopCommonModes];
[inputStream open];
[outputStream open];
self.inputString = [NSMutableString string];
return YES;
}
else
{
[self.connectTimer invalidate];
self.connectTimer = nil;
[delegate messageFailed:self
error:[NSError errorWithDomain:@”SKPSMTPMessageError”
code:kSKPSMTPErrorConnectionFailed
userInfo:[NSDictionary dictionaryWithObject:@”unable to connect to server”
forKey:NSLocalizedDescriptionKey]]];
return NO;
}
}
– (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode
{
switch(eventCode)
{
case NSStreamEventHasBytesAvailable:
{
uint8_t buf[1024];
memset(buf, 0, sizeof(uint8_t) * 1024);
unsigned int len = 0;
len = [(NSInputStream *)stream read:buf maxLength:1024];
if(len)
{
NSString *tmpStr = [[NSString alloc] initWithBytes:buf length:len encoding:NSUTF8StringEncoding];
[inputString appendString:tmpStr];
[tmpStr release];
[self parseBuffer];
}
else
{
}
break;
}
case NSStreamEventEndEncountered:
{
[stream close];
[stream removeFromRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[stream release];
stream = nil; // stream is ivar, so reinit it
if (sendState != kSKPSMTPMessageSent)
{
// TODO: Notify the delegate that there was an error encountered in sending the message
[delegate messageFailed:self
error:[NSError errorWithDomain:@”SKPSMTPMessageError”
code:kSKPSMTPErrorConnectionInterrupted
userInfo:[NSDictionary dictionaryWithObject:@”connection was interrupted”
forKey:NSLocalizedDescriptionKey]]];
}
break;
}
}
}
– (void)parseBuffer
{
// Pull out the next line
NSScanner *scanner = [NSScanner scannerWithString:inputString];
NSString *tmpLine = nil;
NSError *error = nil;
BOOL encounteredError = NO;
BOOL messageSent = NO;
while (![scanner isAtEnd])
{
BOOL foundLine = [scanner scanUpToCharactersFromSet:[NSCharacterSet newlineCharacterSet]
intoString:&tmpLine];
if (foundLine)
{
[self stopWatchdog];
switch (sendState)
{
case kSKPSMTPConnecting:
{
if ([tmpLine hasPrefix:@”220 “])
{
sendState = kSKPSMTPWaitingEHLOReply;
NSString *ehlo = [NSString stringWithFormat:@”EHLO %@\r\n”, @”localhost”];
CFWriteStreamWriteFully((CFWriteStreamRef)outputStream, (const uint8_t *)[ehlo UTF8String], [ehlo lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
[self startShortWatchdog];
}
break;
}
case kSKPSMTPWaitingEHLOReply:
{
// Test auth login options
if ([tmpLine hasPrefix:@”250-AUTH”])
{
NSRange testRange;
testRange = [tmpLine rangeOfString:@”CRAM-MD5″];
if (testRange.location != NSNotFound)
{
serverAuthCRAMMD5 = YES;
}
testRange = [tmpLine rangeOfString:@”PLAIN”];
if (testRange.location != NSNotFound)
{
serverAuthPLAIN = YES;
}
testRange = [tmpLine rangeOfString:@”LOGIN”];
if (testRange.location != NSNotFound)
{
serverAuthLOGIN = YES;
}
testRange = [tmpLine rangeOfString:@”DIGEST-MD5″];
if (testRange.location != NSNotFound)
{
serverAuthDIGESTMD5 = YES;
}
}
else if ([tmpLine hasPrefix:@”250-8BITMIME”])
{
server8bitMessages = YES;
}
else if ([tmpLine hasPrefix:@”250-STARTTLS”] && !isSecure && wantsSecure)
{
// if we’re not already using TLS, start it up
sendState = kSKPSMTPWaitingTLSReply;
NSString *startTLS = @”STARTTLS\r\n”;
CFWriteStreamWriteFully((CFWriteStreamRef)outputStream, (const uint8_t *)[startTLS UTF8String], [startTLS lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
[self startShortWatchdog];
}
else if ([tmpLine hasPrefix:@”250 “])
{
if (self.requiresAuth)
{
// Start up auth
if (serverAuthPLAIN)
{
sendState = kSKPSMTPWaitingAuthSuccess;
NSString *loginString = [NSString stringWithFormat:@”00%@00%@”, login, pass];
NSString *authString = [NSString stringWithFormat:@”AUTH PLAIN %@\r\n”, [[loginString dataUsingEncoding:NSUTF8StringEncoding] encodeBase64ForData]];
CFWriteStreamWriteFully((CFWriteStreamRef)outputStream, (const uint8_t *)[authString UTF8String], [authString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
[self startShortWatchdog];
}
else if (serverAuthLOGIN)
{
sendState = kSKPSMTPWaitingLOGINUsernameReply;
NSString *authString = @”AUTH LOGIN\r\n”;
CFWriteStreamWriteFully((CFWriteStreamRef)outputStream, (const uint8_t *)[authString UTF8String], [authString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
[self startShortWatchdog];
}
else
{
error = [NSError errorWithDomain:@”SKPSMTPMessageError”
code:kSKPSMTPErrorUnsupportedLogin
userInfo:[NSDictionary dictionaryWithObject:@”unsupported login mechanism”
forKey:NSLocalizedDescriptionKey]];
encounteredError = YES;
}
}
else
{
// Start up send from
sendState = kSKPSMTPWaitingFromReply;
NSString *mailFrom = [NSString stringWithFormat:@”MAIL FROM:<%@>\r\n”, fromEmail];
CFWriteStreamWriteFully((CFWriteStreamRef)outputStream, (const uint8_t *)[mailFrom UTF8String], [mailFrom lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
[self startShortWatchdog];
}
}
break;
}
case kSKPSMTPWaitingTLSReply:
{
if ([tmpLine hasPrefix:@”220 “])
{
// Don’t validate SSL certs.
if (!self.validateSSLChain)
{
CFReadStreamSetProperty((CFReadStreamRef)inputStream, kCFStreamSSLValidatesCertificateChain, kCFBooleanFalse);
CFWriteStreamSetProperty((CFWriteStreamRef)outputStream, kCFStreamSSLValidatesCertificateChain, kCFBooleanFalse);
}
// Attempt to use TLSv1
if ( [inputStream setProperty:NSStreamSocketSecurityLevelTLSv1 forKey:NSStreamSocketSecurityLevelKey] &&
[outputStream setProperty:NSStreamSocketSecurityLevelTLSv1 forKey:NSStreamSocketSecurityLevelKey] )
{
// restart the connection
sendState = kSKPSMTPWaitingEHLOReply;
isSecure = YES;
NSString *ehlo = [NSString stringWithFormat:@”EHLO %@\r\n”, @”localhost”];
CFWriteStreamWriteFully((CFWriteStreamRef)outputStream, (const uint8_t *)[ehlo UTF8String], [ehlo lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
[self startShortWatchdog];
}
else
{
error = [NSError errorWithDomain:@”SKPSMTPMessageError”
code:kSKPSMTPErrorTLSFail
userInfo:[NSDictionary dictionaryWithObject:@”Unable to start TLS”
forKey:NSLocalizedDescriptionKey]];
encounteredError = YES;
}
}
}
case kSKPSMTPWaitingLOGINUsernameReply:
{
if ([tmpLine hasPrefix:@”334 VXNlcm5hbWU6″])
{
sendState = kSKPSMTPWaitingLOGINPasswordReply;
NSString *authString = [NSString stringWithFormat:@”%@\r\n”, [[login dataUsingEncoding:NSUTF8StringEncoding] encodeBase64ForData]];
CFWriteStreamWriteFully((CFWriteStreamRef)outputStream, (const uint8_t *)[authString UTF8String], [authString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
[self startShortWatchdog];
}
break;
}
case kSKPSMTPWaitingLOGINPasswordReply:
{
if ([tmpLine hasPrefix:@”334 UGFzc3dvcmQ6″])
{
sendState = kSKPSMTPWaitingAuthSuccess;
NSString *authString = [NSString stringWithFormat:@”%@\r\n”, [[pass dataUsingEncoding:NSUTF8StringEncoding] encodeBase64ForData]];
CFWriteStreamWriteFully((CFWriteStreamRef)outputStream, (const uint8_t *)[authString UTF8String], [authString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
[self startShortWatchdog];
}
break;
}
case kSKPSMTPWaitingAuthSuccess:
{
if ([tmpLine hasPrefix:@”235 “])
{
sendState = kSKPSMTPWaitingFromReply;
NSString *mailFrom = server8bitMessages ? [NSString stringWithFormat:@”MAIL FROM:<%@> BODY=8BITMIME\r\n”, fromEmail] : [NSString stringWithFormat:@”MAIL FROM:<%@>\r\n”, fromEmail];
CFWriteStreamWriteFully((CFWriteStreamRef)outputStream, (const uint8_t *)[mailFrom cStringUsingEncoding:NSASCIIStringEncoding], [mailFrom lengthOfBytesUsingEncoding:NSASCIIStringEncoding]);
[self startShortWatchdog];
}
else if ([tmpLine hasPrefix:@”535 “])
{
error =[NSError errorWithDomain:@”SKPSMTPMessageError”
code:kSKPSMTPErrorInvalidUserPass
userInfo:[NSDictionary dictionaryWithObject:@”login/password invalid”
forKey:NSLocalizedDescriptionKey]];
encounteredError = YES;
}
break;
}
case kSKPSMTPWaitingFromReply:
{
if ([tmpLine hasPrefix:@”250 “])
{
sendState = kSKPSMTPWaitingToReply;
NSMutableString *multipleRcptTo = [NSMutableString string];
[multipleRcptTo appendString:[self formatAddresses:toEmail]];
[multipleRcptTo appendString:[self formatAddresses:ccEmail]];
if (CFWriteStreamWriteFully((CFWriteStreamRef)outputStream, (const uint8_t *)[multipleRcptTo UTF8String], [multipleRcptTo lengthOfBytesUsingEncoding:NSUTF8StringEncoding]) < 0)
{
error =  [outputStream streamError];
encounteredError = YES;
}
else
{
[self startShortWatchdog];
}
}
break;
}
case kSKPSMTPWaitingToReply:
{
if ([tmpLine hasPrefix:@”250 “])
{
sendState = kSKPSMTPWaitingForEnterMail;
NSString *dataString = @”DATA\r\n”;
CFWriteStreamWriteFully((CFWriteStreamRef)outputStream, (const uint8_t *)[dataString UTF8String], [dataString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
[self startShortWatchdog];
}
else if ([tmpLine hasPrefix:@”530 “])
{
error =[NSError errorWithDomain:@”SKPSMTPMessageError”
code:kSKPSMTPErrorNoRelay
userInfo:[NSDictionary dictionaryWithObject:@”relay rejected – server probably requires auth”
forKey:NSLocalizedDescriptionKey]];
encounteredError = YES;
}
break;
}
case kSKPSMTPWaitingForEnterMail:
{
if ([tmpLine hasPrefix:@”354 “])
{
sendState = kSKPSMTPWaitingSendSuccess;
[self sendParts];
}
break;
}
case kSKPSMTPWaitingSendSuccess:
{
if ([tmpLine hasPrefix:@”250 “])
{
sendState = kSKPSMTPWaitingQuitReply;
NSString *quitString = @”QUIT\r\n”;
CFWriteStreamWriteFully((CFWriteStreamRef)outputStream, (const uint8_t *)[quitString UTF8String], [quitString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
[self startShortWatchdog];
}
else if ([tmpLine hasPrefix:@”550 “])
{
error =[NSError errorWithDomain:@”SKPSMTPMessageError”
code:kSKPSMTPErrorInvalidMessage
userInfo:[NSDictionary dictionaryWithObject:@”error sending message”
forKey:NSLocalizedDescriptionKey]];
encounteredError = YES;
}
}
case kSKPSMTPWaitingQuitReply:
{
if ([tmpLine hasPrefix:@”221 “])
{
sendState = kSKPSMTPMessageSent;
messageSent = YES;
}
}
}
}
else
{
break;
}
}
self.inputString = [[[inputString substringFromIndex:[scanner scanLocation]] mutableCopy] autorelease];
if (messageSent)
{
[self cleanUpStreams];
[delegate messageSent:self];
}
else if (encounteredError)
{
[self cleanUpStreams];
[delegate messageFailed:self error:error];
}
}
– (void)sendParts
{
NSMutableString *message = [[NSMutableString alloc] init];
static NSString *separatorString = @”–SKPSMTPMessage–Separator–Delimiter\r\n”;
/** customize change here***/
CFUUIDRef       uuidRef   = CFUUIDCreate(kCFAllocatorDefault);
NSString        *uuid     = (NSString *)CFUUIDCreateString(kCFAllocatorDefault, uuidRef);
CFRelease(uuidRef);
NSDate *now = [[NSDate alloc] init];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@”EEE, dd MMM yyyy HH:mm:ss Z”];
[message appendFormat:@”Date: %@\r\n”, [dateFormatter stringFromDate:now]];
[message appendFormat:@”Message-id: <%@@%@>\r\n”, [(NSString *)uuid stringByReplacingOccurrencesOfString:@”-” withString:@””], self.relayHost];
[now release];
[dateFormatter release];
[uuid release];
/*********till now*************/
[message appendFormat:@”From:%@\r\n”, fromEmail];
/*****/
if ((self.toEmail != nil) && (![self.toEmail isEqualToString:@””]))
{
[message appendFormat:@”To:%@\r\n”, self.toEmail];
}
if ((self.ccEmail != nil) && (![self.ccEmail isEqualToString:@””]))
{
[message appendFormat:@”Cc:%@\r\n”, self.ccEmail];
}
/*******/
[message appendString:@”Content-Type: multipart/mixed; boundary=SKPSMTPMessage–Separator–Delimiter\r\n”];
[message appendString:@”Mime-Version: 1.0 (SKPSMTPMessage 1.0)\r\n”];
[message appendFormat:@”Subject:%@\r\n\r\n”,subject];
[message appendString:separatorString];
NSData *messageData = [message dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
CFWriteStreamWriteFully((CFWriteStreamRef)outputStream, (const uint8_t *)[messageData bytes], [messageData length]);
[message release];
message = [[NSMutableString alloc] init];
for (NSDictionary *part in parts)
{
if ([part objectForKey:kSKPSMTPPartContentDispositionKey])
{
[message appendFormat:@”Content-Disposition: %@\r\n”, [part objectForKey:kSKPSMTPPartContentDispositionKey]];
}
[message appendFormat:@”Content-Type: %@\r\n”, [part objectForKey:kSKPSMTPPartContentTypeKey]];
[message appendFormat:@”Content-Transfer-Encoding: %@\r\n\r\n”, [part objectForKey:kSKPSMTPPartContentTransferEncodingKey]];
[message appendString:[part objectForKey:kSKPSMTPPartMessageKey]];
[message appendString:@”\r\n”];
[message appendString:separatorString];
}
[message appendString:@”\r\n.\r\n”];
CFWriteStreamWriteFully((CFWriteStreamRef)outputStream, (const uint8_t *)[message UTF8String], [message lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
[self startLongWatchdog];
[message release];
//return YES;
}
– (void)connectionConnectedCheck:(NSTimer *)aTimer
{
if (sendState == kSKPSMTPConnecting)
{
[inputStream close];
[inputStream removeFromRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[inputStream release];
inputStream = nil;
[outputStream close];
[outputStream removeFromRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[outputStream release];
outputStream = nil;
// Try the next port – if we don’t have another one to try, this will fail
sendState = kSKPSMTPIdle;
[self send];
}
self.connectTimer = nil;
}
– (void)connectionWatchdog:(NSTimer *)aTimer
{
[self cleanUpStreams];
// No hard error if we’re wating on a reply
if (sendState != kSKPSMTPWaitingQuitReply)
{
NSError *error = [NSError errorWithDomain:@”SKPSMTPMessageError” code:kSKPSMPTErrorConnectionTimeout userInfo:[NSDictionary dictionaryWithObject:@”timeout sending message”
forKey:NSLocalizedDescriptionKey]];
[delegate messageFailed:self error:error];
}
else
{
[delegate messageSent:self];
}
}
– (void)cleanUpStreams
{
[inputStream close];
[inputStream removeFromRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[inputStream release];
inputStream = nil;
[outputStream close];
[outputStream removeFromRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[outputStream release];
outputStream = nil;
}
– (NSString *)formatAnAddress:(NSString *)address {
NSString                *formattedAddress;
NSCharacterSet  *whitespaceCharSet = [NSCharacterSet whitespaceCharacterSet];
if (([address rangeOfString:@”<“].location == NSNotFound) && ([address rangeOfString:@”>”].location == NSNotFound)) {
formattedAddress = [NSString stringWithFormat:@”RCPT TO:<%@>\r\n”, [address stringByTrimmingCharactersInSet:whitespaceCharSet]];
}
else {
formattedAddress = [NSString stringWithFormat:@”RCPT TO:%@\r\n”, [address stringByTrimmingCharactersInSet:whitespaceCharSet]];
}
return(formattedAddress);
}
– (NSString *)formatAddresses:(NSString *)addresses {
NSCharacterSet  *splitSet = [NSCharacterSet characterSetWithCharactersInString:@”;,”];
NSMutableString *multipleRcptTo = [NSMutableString string];
if ((addresses != nil) && (![addresses isEqualToString:@””])) {
if( [addresses rangeOfString:@”;”].location != NSNotFound || [addresses rangeOfString:@”,”].location != NSNotFound ) {
NSArray *addressParts = [addresses componentsSeparatedByCharactersInSet:splitSet];
for( NSString *address in addressParts ) {
[multipleRcptTo appendString:[self formatAnAddress:address]];
}
}
else {
[multipleRcptTo appendString:[self formatAnAddress:addresses]];
}
}
return(multipleRcptTo);
}
@end
– now import following files from your .h class.
#import <CFNetwork/CFNetwork.h>
#import “SKPSMTPMessage.h”
#import “NSData+Base64Additions.h”
– now add a smtp delegate (SKPSMTPMessageDelegate) to your class
– now add this function in your class
– (void)sendMessage{
SKPSMTPMessage *testMsg = [[SKPSMTPMessage alloc] init];
testMsg.fromEmail = delegate.userEmail;
testMsg.toEmail = email address;
testMsg.relayHost = @”smtp.gmail.com”;
testMsg.requiresAuth = YES;
testMsg.login = login address;
testMsg.pass = login password;
testMsg.subject = subject text;
testMsg.wantsSecure = YES;
testMsg.delegate = self;
NSDictionary *plainPart = [NSDictionary dictionaryWithObjectsAndKeys:@”text/plain”,kSKPSMTPPartContentTypeKey,
your comment text part,kSKPSMTPPartMessageKey,@”8bit”,kSKPSMTPPartContentTransferEncodingKey,nil];
NSString *vcfPath = [[NSBundle mainBundle] pathForResource:@”filename” ofType:@”extention”];
NSData *vcfData = [NSData dataWithContentsOfFile:vcfPath];
NSDictionary *vcfPart = [NSDictionary dictionaryWithObjectsAndKeys:@”text/directory;\r\n\tx-unix-mode=0644;\r\n\tname=\”filename.extention\””,kSKPSMTPPartContentTypeKey,
@”attachment;\r\n\tfilename=\”filename.extention\””,kSKPSMTPPartContentDispositionKey,[vcfData encodeBase64ForData],kSKPSMTPPartMessageKey,@”base64″,kSKPSMTPPartContentTransferEncodingKey,nil];
testMsg.parts = [NSArray arrayWithObjects:plainPart,
vcfPart,
nil];
[testMsg send];
}
– now add two delegate method in your class
1. – (void)messageFailed:(SKPSMTPMessage *)message error:(NSError *)error{
[message release];
}
2. – (void)messageSent:(SKPSMTPMessage *)message{
[message release];
}
– now call sendMessage method and send file or text or both to specific valid email
Advertisements

4 thoughts on “send email with attaching file using smtp server

  1. Thanks for the unique tips discussed on this blog. I have observed that many insurers offer prospects generous special discounts if they choose to insure a few cars with them. A significant volume of households possess several autos these days, specially those with elderly teenage youngsters still living at home, as well as the savings on policies may soon mount up. So it is a good idea to look for a good deal.

  2. After review several with the blog posts in your internet site now, and I truly like your means of blogging. I bookmarked it to my bookmark web site record and might be checking back soon. Pls have a look at my internet web site too and allow me to know what you believe.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s