如何在目标c中使用oauth身份验证而不是用户名和密码来发送电子邮件

时间:2014-03-02 14:40:01

标签: ios objective-c oauth smtp

我正在开发一个必须允许自动发送电子邮件的iPhone应用程序,无需任何用户交互(我不能使用MFMailComposeViewController,也不能存储用户的用户名/密码,以便将它们与SKPSMTP或MailCore等SMTP库一起使用)。 我的想法是允许用户使用OAuth协议使用他的Gmail帐户登录,然后在其他时刻使用先前给出的access_token,用于发送电子邮件而无需重新进行身份验证或询问用户是否有任何其他数据。 我使用GoogleOpenSource.framework和GooglePlus.framework登录用户。 任何建议都会有所帮助。 提前谢谢。

2 个答案:

答案 0 :(得分:0)

您应该可以使用带有此SMTP命令的OAUTH令牌对GMAIL smtp服务器进行身份验证:

AUTH XOAUTH <your OAUTH token>

Google here记录了OAUTH与GMail SMTP服务器的使用情况。 您会在Google上找到there个更多文档,包括以下SMTP OAUTH会话示例:

[connection begins]
S: 220 mx.google.com ESMTP 12sm2095603fks.9
C: EHLO sender.example.com
S: 250-mx.google.com at your service, [172.31.135.47]
S: 250-SIZE 35651584
S: 250-8BITMIME
S: 250-AUTH LOGIN PLAIN XOAUTH
S: 250-ENHANCEDSTATUSCODES
S: 250 PIPELINING
C: AUTH XOAUTH R0VUIGh0dHBzOi8vbWFpbC5nb29nbGUuY29tL21ha
WwvYi9zb21ldXNlckBleGFtcGxlLmNvbS9zbXRwLyBvYXV0aF9jb25zd
W1lcl9rZXk9ImFub255bW91cyIsb2F1dGhfbm9uY2U9IjIwNDg1MjE2O
DgzNjgyNzY0MzAiLG9hdXRoX3NpZ25hdHVyZT0iVEJNQmo2NG9ZMzNJd
ERUOWxtUGlveGF0Uko0JTNEIixvYXV0aF9zaWduYXR1cmVfbWV0aG9kP
SJITUFDLVNIQTEiLG9hdXRoX3RpbWVzdGFtcD0iMTI2NzIwNTc2OSIsb
2F1dGhfdG9rZW49ImFzZGZhc2RmIixvYXV0aF92ZXJzaW9uPSIxLjAi
S: 235 2.7.0 Accepted
[connection continues...]

我不熟悉iPhone开发,因此我无法为您提供一些示例代码。但是您需要一个支持扩展身份验证方案的SMTP库。

答案 1 :(得分:0)

最后,我找到了解决问题的方法。接下来,我详细介绍了使用OAuth身份验证向Google发送电子邮件的步骤:

对于OAuth登录,我使用了GooglePlus.framework中包含的GPPSignIn类。如果您感兴趣,请按照herehere列出的说明操作。 在登录窗口中,完成该过程后,将调用下一个委托方法:

- (void)finishedWithAuth: (GTMOAuth2Authentication *)auth error: (NSError *) error {
    NSLog(@"Received error %@ and auth object %@",error, auth);
    if(error) {
        NSLog(@"%@",[error description]);
    }
    else {
        // Get the refresh token.
        self.refreshToken = auth.refreshToken;

        // If you need the user's email you must set the permissions on the GPPSignIn instance.
        // store it locally for future uses.
        self.email = [GPPSignIn sharedInstance].userEmail;
    }
}

然后,为了发送电子邮件,我使用了MailCore的库。 如果您要发送包含OAuth accessToken的电子邮件,首先必须使用先前在登录过程中保存的刷新令牌获取更新的令牌:

- (void)sendMail {

    GTMOAuth2Authentication * auth = [GTMOAuth2ViewControllerTouch authForGoogleFromKeychainForName:GOOGLE_OAUTH_KEYCHAIN clientID:GOOGLE_CLIENT_ID clientSecret:GOOGLE_CLIENT_SECRET];

    //I use the saved refreshToken    
    auth.refreshToken = refreshToken;


    [auth beginTokenFetchWithDelegate:self
                didFinishSelector:@selector(auth:finishedRefreshWithFetcher:error:)];

}

- (void)auth:(GTMOAuth2Authentication *)auth finishedRefreshWithFetcher:(GTMHTTPFetcher *)fetcher error:(NSError *)error {

    if (error != nil) {
         NSLog(@"Authentication failed");
         return;
    }

    NSString * email = storedEmail;
    NSString * accessToken = [auth accessToken];


    MCOSMTPSession * smtpSession = [[MCOSMTPSession alloc] init];

    smtpSession = [[MCOSMTPSession alloc] init];
    smtpSession.hostname = @"smtp.gmail.com";
    smtpSession.port = 465;
    smtpSession.username = email; //saved value
    smtpSession.connectionType = MCOConnectionTypeTLS;
    smtpSession.password = nil; //nil
    smtpSession.OAuth2Token = accessToken; //saved value
    smtpSession.authType = MCOAuthTypeXOAuth2;

    MCOMessageBuilder * builder = [[MCOMessageBuilder alloc] init];

    MCOAddress *fromAddress = [MCOAddress addressWithMailbox:email];
    MCOAddress *toAddress = [MCOAddress addressWithMailbox:recipientEmail];

    [[builder header] setFrom:fromAddress];
    [[builder header] setTo:toAddresses];
    [[builder header] setSubject:@"Some subject"];
    [builder setHTMLBody:@"some message"];
    NSData * rfc822Data = [builder data];

    MCOSMTPSendOperation *sendOperation = [smtpSession sendOperationWithData:rfc822Data];
    [sendOperation start:^(NSError *error) {
        if(error) {
            NSLog(@"%@ Error sending email:%@", email, error);
        } else {
            NSLog(@"%@ Successfully sent email!", email);
        }
    }];
}