1

我们正在开发一个涉及通过 Gmail API 发送电子邮件的 iOS 项目,但我们无法找到有关如何实际执行此操作的文档。

首先,我们还没有完全弄清楚身份验证。我们正在使用AppAuth来处理这个问题,到目前为止它工作得很好,但是我们不太确定如何在我们的代码中将它链接到 Gmail API。

其次,我们如何发送消息本身?我们已经格式化了内容和所有内容,我们只是无法弄清楚如何实际发送消息。我们要做的就是从用户自己的电子邮件帐户向指定的电子邮件地址发送一条简单的消息;没有附件或类似的东西。我们已经看到了几个 swift 示例,但是我们更喜欢使用 Objective C。关于我们如何做到这一点的任何想法?

更新:

在尝试了更多之后,我们找到了另一种连接到 Gmail 的方法。我们没有使用来自 Google API Objective C Client for REST 的类,而是尝试使用 HTTP POST 方法发送电子邮件。这似乎比处理我们之前遇到的所有错误要容易得多。我们现在唯一的问题是我们仍然不能完全发送消息。几乎所有我们都尝试过,API 只是创建一个空消息并将其放入我们的已发送邮箱;而已。这是我们现在所拥有的:

- (void)sendEmail{
    NSURL *userinfoEndpoint = [NSURL URLWithString:@"https://www.googleapis.com/upload/gmail/v1/users/TEST_USERNAME/messages/send?uploadType=media"];
    NSString *currentAccessToken = _authState.lastTokenResponse.accessToken;

    [self logMessage:@"Trying to authenticate...."];

    // Handle refreshing tokens

    NSString *message = [NSString stringWithFormat:@"{\"raw\": \"%@\"}",[self generateMessage]];
    NSLog(@"%@", message);

    // creates request to the userinfo endpoint, with access token in the Authorization header
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:userinfoEndpoint];
    NSString *authorizationHeaderValue = [NSString stringWithFormat:@"Bearer %@", accessToken];
    [request addValue:authorizationHeaderValue forHTTPHeaderField:@"Authorization"];
    [request setHTTPMethod:@"POST"];
    [request setValue:@"message/rfc822" forHTTPHeaderField:@"Content-Type"];
    [request setValue:[NSString stringWithFormat:@"%lu", (unsigned long)[message length]] forHTTPHeaderField:@"Content-Length"];
    [request setHTTPBody:[message dataUsingEncoding:NSUTF8StringEncoding];

    NSURLSessionConfiguration *configuration =
    [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
                                                          delegate:nil
                                                     delegateQueue:nil];
    // performs HTTP request
    NSURLSessionDataTask *postDataTask =
    [session dataTaskWithRequest:request
               completionHandler:^(NSData *_Nullable data,
                                   NSURLResponse *_Nullable response,
                                   NSError *_Nullable error) {
                  // Handle response
               }];

    [postDataTask resume];
}];

}
- (NSString *)generateMessage{
    NSString *message = [NSString stringWithFormat:@"From: <TEST_USER@domain.com>\nTo: <TEST_USER@domain.com>\nSubject: Test\n\nThis is a test"];
    NSString *rawMessage = [message stringByReplacingOccurrencesOfString:@"\\n" withString:@"\n"];

    NSData *encodedMessage = [rawMessage dataUsingEncoding:NSUTF8StringEncoding];
    NSString *encoded = [encodedMessage base64EncodedStringWithOptions:0];
    NSLog(@"%@", encoded);

    return encoded;
}

我们已经测试了编码部分,它正在制作一个正确的 base64 字符串,但是在那之后,某些东西的格式显然不正确。我们得到消息已成功创建的确认信息,但 API 所做的只是创建一个没有收件人、主题或正文的空电子邮件。关于我们可以做些什么来让它发挥作用的任何想法?

4

2 回答 2

0

我不是这方面的专家,但我记得我们过去做过类似的事情。按照以下链接中的说明进行操作,并确保您在 Gmail API 向导中选择了正确的选项

https://developers.google.com/gmail/api/quickstart/ios?ver=objc

在此处输入图像描述

在此处输入图像描述

我希望这个对你有用

于 2017-03-14T03:57:38.580 回答
0

经过无数次实验,这里的代码似乎最终对我有用,我从上面的示例中完成了它。

首先,您需要在开发控制台中创建 google 项目,获取其客户端 ID 和 Api-Key(这可能不是必需的)并在 AppDelegete 中实现 Google SignIn - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)启动选项方法:

[GIDSignIn sharedInstance].clientID = @"your proj client id here";
[GIDSignIn sharedInstance].delegate = self;
[GIDSignIn sharedInstance].scopes=[NSArray arrayWithObjects:@"https://www.googleapis.com/auth/gmail.send",@"https://www.googleapis.com/auth/gmail.readonly",@"https://www.googleapis.com/auth/gmail.modify", nil];

现在发送电子邮件:

// refresh token
appDelegate.delAuthAccessToken=@"";
[[GIDSignIn sharedInstance] signInSilently];
NSDate *timeStart = [NSDate date];
NSTimeInterval timeSinceStart=0;
while([appDelegate.delAuthAccessToken isEqualToString:@""] && timeSinceStart<10){//wait for new token but no longer than 10s should be enough
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                             beforeDate:[NSDate dateWithTimeIntervalSinceNow:1.0f]];//1sec increment actually ~0.02s
    timeSinceStart = [[NSDate date] timeIntervalSinceDate:timeStart];
}
if (timeSinceStart>=10) {//timed out
    return;
}

//compose rfc2822 message AND DO NOT base64 ENCODE IT and DO NOT ADD {raw etc} TOO, put 'To:' 1st, add \r\n between the lines and double that before the actual text message
NSString *message = [NSString stringWithFormat:@"To: %@\r\nFrom: %@\r\nSubject: EzPic2Txt\r\n\r\n%@", appDelegate.delToEmails, appDelegate.delAuthUserEmail, appDelegate.delMessage];

NSURL *userinfoEndpoint = [NSURL URLWithString:@"https://www.googleapis.com/upload/gmail/v1/users/me/messages/send?uploadType=media"];

NSLog(@"%@", message);

//create request
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:userinfoEndpoint];
[request setHTTPMethod:@"POST"];
[request setHTTPBody:[message dataUsingEncoding:NSUTF8StringEncoding]];//message is plain UTF8 string

//add all headers into session config, maybe ok adding to request too
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
configuration.requestCachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
configuration.HTTPAdditionalHeaders = @{
 @"api-key"       : @"api-key here, may not need it though",
 @"Authorization" : [NSString stringWithFormat:@"Bearer %@", appDelegate.delAuthAccessToken],
 @"Content-type"  : @"message/rfc822",
 @"Accept"        : @"application/json",
 @"Content-Length": [NSString stringWithFormat:@"%lu", (unsigned long)[message length]]
 };
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];

 // performs HTTP request
NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request
                                                completionHandler:^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError *_Nullable error) {
                                                    // Handle response
                                                }];
 [postDataTask resume];

希望它可以帮助某人

在我的应用程序中,我曾经能够使用 MailCore2,但它被 Google 阻止了(当我切换到允许的发送、只读和修改范围时,我的访问被拒绝),因为 MailCore2 仅适用于 FULL 权限。Google 允许使用仅发送、只读和修改范围。不过,没有指导方针如何在 iOS 中将他们的“伟大的宁静 api”与 Gmail 一起使用,所以 HTTP POST 似乎是最后的手段,直到他们也将其关闭。

我不能让 Google 认为我的应用程序不安全。如果您对此感到满意,您仍然可以使用 MailCore2,没问题。

使用 HTTP GET 接收电子邮件:

第一次获得最多 20 条未读消息 ID:

//get IDs of no more than 20 unread messages
//in query you can add extra filters, say messages only from specific emails
NSString *query=@"from:aaa@gmail.com|from:bbb@yahoo.com";
NSString *tmpStr=[NSString stringWithFormat:@"https://www.googleapis.com/gmail/v1/users/me/messages?maxResults=20&q=\"is:unread\" \"%@\"",query];
NSString *tmpStrURL=[tmpStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *userinfoEndpoint = [NSURL URLWithString:tmpStrURL];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:userinfoEndpoint];

[request setHTTPMethod:@"GET"];

NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
configuration.requestCachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
configuration.HTTPAdditionalHeaders = @{@"api-key"       : @"your api key here",
                                        @"Authorization" : [NSString stringWithFormat:@"Bearer %@", yourTokenHere],
                                        @"Accept"        : @"application/json"
                                        };
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
// performs HTTP request
NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request
                                                completionHandler:^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError *_Nullable error) {
                                                    // Handle response
                                                    if (!error){
                                                        NSMutableDictionary *jsondata = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
                                                        long jsonMsgsCnt = [[jsondata valueForKey:@"resultSizeEstimate"] longValue];
                                                        if(jsonMsgsCnt>0){
                                                            NSMutableArray *jsonMsgs = [jsondata objectForKey:@"messages"];
                                                            for (NSMutableDictionary *tmp in jsonMsgs){
                                                                [delMsgsReceived  addObject:[tmp objectForKey:@"id"]];
                                                            }
                                                        }
                                                      NSLog(@"retrieve Email Id postDataTask n msg:%li",delMsgsReceived.count);
                                                    }else{
                                                     NSLog(@"retrieve Email Id postDataTask error:%@",error.description);
                                                    }
                                                }];
[postDataTask resume];

现在 delMsgsReceived 包含 messagesIds。处理它们以一一获取实际的电子邮件:

NSString *tmpStr=[NSString stringWithFormat:@"https://www.googleapis.com/gmail/v1/users/me/messages/%@?format=full", msgId];//supply message id here 
NSString *tmpStrURL=[tmpStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *userinfoEndpoint = [NSURL URLWithString:tmpStrURL];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:userinfoEndpoint];

[request setHTTPMethod:@"GET"];

NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
configuration.requestCachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
configuration.HTTPAdditionalHeaders = @{
                                        @"api-key"       : @"your api key",
                                        @"Authorization" : [NSString stringWithFormat:@"Bearer %@", your auth token],
                                        @"Accept"        : @"application/json"
                                        };
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];

// performs HTTP request
NSURLSessionDataTask *postDataTask =
[session dataTaskWithRequest:request
           completionHandler:^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError *_Nullable error) {
               // Handle response
               if (!error){
                   NSMutableDictionary *jsondata = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
                   NSString *body=[jsondata objectForKey:@"snippet"];//not full msg! 
//for full message get the whole payload and extract what you need from there NSMutableArray *jsonPayload = [[jsondata objectForKey:@"payload"] objectForKey:@"headers"];
               }else{
                   //deal with error
                   NSLog(@"retrieving message error:%@",error.description);
               }
           }];
[postDataTask resume];
于 2019-07-25T20:38:14.673 回答