如何使用POST请求向iOS发送照片电子邮件附件到SendGrid?

时间:2022-12-01 16:31:08

I am using NSMutableURLRequest to send POST data to a server-side PHP script that sends emails using SendGrid. This works just fine. However, I have no idea how to package UIImagedata properly to send as an attachment. Here is my current code:

我正在使用NSMutableURLRequest将POST数据发送到使用SendGrid发送电子邮件的服务器端PHP脚本。这很好用。但是,我不知道如何正确打包UIImagedata以作为附件发送。这是我目前的代码:

// Choose an image from your photo library
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
    chosenImage = info[UIImagePickerControllerEditedImage]; // chosenImage = UIImage
    pickedData = UIImagePNGRepresentation(chosenImage);  // pickedData = NSData
    attachment = TRUE;
    [picker dismissViewControllerAnimated:YES completion:NULL];
}

-(void)sendMail {
    toEmailAddress = @"blabla@blabla.com";
    subject = @"Some Subject";
    message = @"Some message...";
    fullName = @"Mister Bla Bla";

    if (attachment == TRUE) {
        // Create NSData object as PNG image data from camera image
        NSString *picAttachment = [NSString stringWithFormat:@"%lu",(unsigned long)[pickedData length]];
        NSString *picName = @"Photo";
        post = [NSString stringWithFormat:@"&toEmailAddress=%@&subject=%@&message=%@&fullName=%@&picAttachment=%@&picName=%@", toEmailAddress, subject, message, fullName, picAttachment, picName];
    } else {
        post = [NSString stringWithFormat:@"&toEmailAddress=%@&subject=%@&message=%@&fullName=%@", toEmailAddress, subject, message, fullName];
    }

    NSData * postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:NO];
    NSString * postLength = [NSString stringWithFormat:@"%lu",(unsigned long)[postData length]];
    NSMutableURLRequest * request = [[[NSMutableURLRequest alloc] init] autorelease];
    [request setURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://www.someURL.com/sendgrid.php"]]];
    [request setHTTPMethod:@"POST"];
    [request setValue:postLength forHTTPHeaderField:@"Content-Length"];
    [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
    [request setHTTPBody:postData];

    // send the POST request, and read the reply by creating a new NSURLSession:
    NSURLSession *conn = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
    [[conn dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        NSString *requestReply = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
        NSLog(@"requestReply: %@", requestReply); // Return response from PHP script on server.
    }] resume];
}

If you research this question, you may find that there is an existing iOS SendGrid lib. Unfortunately, this is not the answer. The folks at SendGrid tell me not to use the lib because of a security concern.

如果您研究此问题,您可能会发现现有的iOS SendGrid库。不幸的是,这不是答案。由于安全问题,SendGrid的人告诉我不要使用lib。

1 个解决方案

#1


3  

New answer:

To upload file as email attachement directly to SendGrid you should use Web API v3 and create request as described in docs.

要将文件作为电子邮件附件直接上传到SendGrid,您应该使用Web API v3并按照文档中的说明创建请求。

First of all, you need to add authentication header to your request. Secondly, you need to convert your data to JSON format. If we are talking about files, you need to encode you file data with Base64, as described in body parameters section:

首先,您需要为您的请求添加身份验证标头。其次,您需要将数据转换为JSON格式。如果我们正在讨论文件,您需要使用Base64对文件数据进行编码,如主体参数部分所述:

JSON PARAMETER: attachements/content
TYPE: string
REQUIRED: Yes
The Base64 encoded content of the attachment.

Also, take a look to disposition and content_id params: they will help you to setup your file appearance in mail.

另外,看看disposition和content_id参数:它们将帮助您在邮件中设置文件外观。

Old answer:

The standard way of uploading both parameters and files is using POST request with multipart messages. I have change your code to create data of this format:

上传参数和文件的标准方法是使用带有多部分消息的POST请求。我已更改您的代码以创建此格式的数据:

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
  UIImage* image = info[UIImagePickerControllerEditedImage];
  NSDictionary* params = @{
    @"toEmailAddress" : @"blabla@blabla.com",
    @"subject" : @"Some Subject",
    @"message" : @"Some message...",
    @"fullName" : @"Mister Bla Bla",
  };
  [picker dismissViewControllerAnimated:YES completion:^{
    [self sendMailWithParams:params image:image];
  }];
}

static NSStringEncoding const kEncoding = NSUTF8StringEncoding;

- (void)sendMailWithParams:(NSDictionary*)params image:(UIImage*)image {
  NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
  request.URL = [NSURL URLWithString:@"http://www.someURL.com/sendgrid.php"];
  request.HTTPMethod = @"POST";

  NSString *boundary = [NSUUID UUID].UUIDString;

  // define POST request as multipart
  NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
  [request addValue:contentType forHTTPHeaderField: @"Content-Type"];

  // prepare boundary
  NSString *middleBoundary = [NSString stringWithFormat:@"--%@\r\n", boundary];
  NSData *middleBoundaryData = [middleBoundary dataUsingEncoding:kEncoding];

  NSMutableData* body = [NSMutableData data];

  // append params
  [params enumerateKeysAndObjectsUsingBlock:^(NSString* key, NSString* value, BOOL* stop) {
    [body appendData:middleBoundaryData];
    NSData* fieldData = [self dataForKey:key value:value];
    [body appendData:fieldData];
  }];

  // append image
  if (image) {
    [body appendData:middleBoundaryData];
    NSData* imageData = [self dataForImage:image imageName:@"photo.png"];
    [body appendData:imageData];
  }

  // add last boundary
  NSString* lastBoundary = [NSString stringWithFormat:@"--%@--\r\n", boundary];
  NSData* lastBoundaryData = [lastBoundary dataUsingEncoding:kEncoding];
  [body appendData:lastBoundaryData];

  // set body to request
  request.HTTPBody = body;

  // add length of body
  NSString *length = [NSString stringWithFormat:@"%llu", (uint64_t)body.length];
  [request setValue:length forHTTPHeaderField:@"Content-Length"];

  // send request
  NSURLSession* session = [NSURLSession sharedSession];
  NSURLSessionDataTask* task = [session dataTaskWithRequest:request
                                          completionHandler:^(NSData *data,
                                                              NSURLResponse *response,
                                                              NSError *error) {
    // handle as you want
  }];
  [task resume];
}

- (NSData*)dataForImage:(UIImage*)image imageName:(NSString*)imageName {
  NSString* fieldDescription = [NSString stringWithFormat:
      @"Content-Disposition: form-data; name=\"image\"; filename=\"%@\"\r\n"
      @"Content-Type: image/png\r\n\r\n", imageName];

  NSMutableData *data = [NSMutableData data];
  [data appendData:[fieldDescription dataUsingEncoding:kEncoding]];

  NSData* imageData = UIImagePNGRepresentation(image);
  [data appendData:imageData];

  NSString* newLine = @"\r\n";
  NSData* newLineData = [newLine dataUsingEncoding:kEncoding];
  [data appendData:newLineData];

  return data;
}

- (NSData*)dataForKey:(NSString*)key value:(NSString*)value {
  NSString* fieldDescription = [NSString stringWithFormat:
      @"Content-Disposition: form-data; name=\"%@\"\r\n\r\n"
      @"%@\r\n", key, value];
  return [fieldDescription dataUsingEncoding:kEncoding];
}

You can use $_POST and $_FILES variables to get access to loaded data in your PHP script. If you want to learn more about multipart messages, check docs here.

您可以使用$ _POST和$ _FILES变量来访问PHP脚本中的已加载数据。如果您想了解有关多部分消息的更多信息,请在此处查看文档。

#1


3  

New answer:

To upload file as email attachement directly to SendGrid you should use Web API v3 and create request as described in docs.

要将文件作为电子邮件附件直接上传到SendGrid,您应该使用Web API v3并按照文档中的说明创建请求。

First of all, you need to add authentication header to your request. Secondly, you need to convert your data to JSON format. If we are talking about files, you need to encode you file data with Base64, as described in body parameters section:

首先,您需要为您的请求添加身份验证标头。其次,您需要将数据转换为JSON格式。如果我们正在讨论文件,您需要使用Base64对文件数据进行编码,如主体参数部分所述:

JSON PARAMETER: attachements/content
TYPE: string
REQUIRED: Yes
The Base64 encoded content of the attachment.

Also, take a look to disposition and content_id params: they will help you to setup your file appearance in mail.

另外,看看disposition和content_id参数:它们将帮助您在邮件中设置文件外观。

Old answer:

The standard way of uploading both parameters and files is using POST request with multipart messages. I have change your code to create data of this format:

上传参数和文件的标准方法是使用带有多部分消息的POST请求。我已更改您的代码以创建此格式的数据:

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
  UIImage* image = info[UIImagePickerControllerEditedImage];
  NSDictionary* params = @{
    @"toEmailAddress" : @"blabla@blabla.com",
    @"subject" : @"Some Subject",
    @"message" : @"Some message...",
    @"fullName" : @"Mister Bla Bla",
  };
  [picker dismissViewControllerAnimated:YES completion:^{
    [self sendMailWithParams:params image:image];
  }];
}

static NSStringEncoding const kEncoding = NSUTF8StringEncoding;

- (void)sendMailWithParams:(NSDictionary*)params image:(UIImage*)image {
  NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
  request.URL = [NSURL URLWithString:@"http://www.someURL.com/sendgrid.php"];
  request.HTTPMethod = @"POST";

  NSString *boundary = [NSUUID UUID].UUIDString;

  // define POST request as multipart
  NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
  [request addValue:contentType forHTTPHeaderField: @"Content-Type"];

  // prepare boundary
  NSString *middleBoundary = [NSString stringWithFormat:@"--%@\r\n", boundary];
  NSData *middleBoundaryData = [middleBoundary dataUsingEncoding:kEncoding];

  NSMutableData* body = [NSMutableData data];

  // append params
  [params enumerateKeysAndObjectsUsingBlock:^(NSString* key, NSString* value, BOOL* stop) {
    [body appendData:middleBoundaryData];
    NSData* fieldData = [self dataForKey:key value:value];
    [body appendData:fieldData];
  }];

  // append image
  if (image) {
    [body appendData:middleBoundaryData];
    NSData* imageData = [self dataForImage:image imageName:@"photo.png"];
    [body appendData:imageData];
  }

  // add last boundary
  NSString* lastBoundary = [NSString stringWithFormat:@"--%@--\r\n", boundary];
  NSData* lastBoundaryData = [lastBoundary dataUsingEncoding:kEncoding];
  [body appendData:lastBoundaryData];

  // set body to request
  request.HTTPBody = body;

  // add length of body
  NSString *length = [NSString stringWithFormat:@"%llu", (uint64_t)body.length];
  [request setValue:length forHTTPHeaderField:@"Content-Length"];

  // send request
  NSURLSession* session = [NSURLSession sharedSession];
  NSURLSessionDataTask* task = [session dataTaskWithRequest:request
                                          completionHandler:^(NSData *data,
                                                              NSURLResponse *response,
                                                              NSError *error) {
    // handle as you want
  }];
  [task resume];
}

- (NSData*)dataForImage:(UIImage*)image imageName:(NSString*)imageName {
  NSString* fieldDescription = [NSString stringWithFormat:
      @"Content-Disposition: form-data; name=\"image\"; filename=\"%@\"\r\n"
      @"Content-Type: image/png\r\n\r\n", imageName];

  NSMutableData *data = [NSMutableData data];
  [data appendData:[fieldDescription dataUsingEncoding:kEncoding]];

  NSData* imageData = UIImagePNGRepresentation(image);
  [data appendData:imageData];

  NSString* newLine = @"\r\n";
  NSData* newLineData = [newLine dataUsingEncoding:kEncoding];
  [data appendData:newLineData];

  return data;
}

- (NSData*)dataForKey:(NSString*)key value:(NSString*)value {
  NSString* fieldDescription = [NSString stringWithFormat:
      @"Content-Disposition: form-data; name=\"%@\"\r\n\r\n"
      @"%@\r\n", key, value];
  return [fieldDescription dataUsingEncoding:kEncoding];
}

You can use $_POST and $_FILES variables to get access to loaded data in your PHP script. If you want to learn more about multipart messages, check docs here.

您可以使用$ _POST和$ _FILES变量来访问PHP脚本中的已加载数据。如果您想了解有关多部分消息的更多信息,请在此处查看文档。