以编程方式通过电子邮件发送iphone附件

时间:2011-10-19 16:25:57

标签: iphone email

我正在编写一个iPhone应用程序,要求我以编程方式发送电子邮件附件。附件是一个csv文件,我通过代码创建。然后我将文件附加到电子邮件中,附件显示在手机上。但是,当我向自己发送电子邮件时,附件不会出现在电子邮件中。这是我正在使用的代码。

    [self exportData];

if ([MFMailComposeViewController canSendMail])
{
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"expenses" ofType:@"csv"];  
    NSData *myData = [NSData dataWithContentsOfFile:filePath]; 

    MFMailComposeViewController *mailer = [[MFMailComposeViewController alloc] init];

    mailer.mailComposeDelegate = self;

    [mailer setSubject:@"Vehicle Expenses from myConsultant"];

    NSString *emailBody = @"";
    [mailer setMessageBody:emailBody isHTML:NO];

    [mailer addAttachmentData:myData mimeType:@"text/plain" fileName:@"expenses"];

    [self presentModalViewController:mailer animated:YES];

    [mailer release]; 
}
else
{
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Failure"
                                                    message:@"Your device doesn't support the composer sheet"
                                                   delegate:nil
                                          cancelButtonTitle:@"OK"
                                          otherButtonTitles:nil];
    [alert show];
    [alert release];
}
}
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{
    switch (result)
    {
        case MFMailComposeResultCancelled:
            NSLog(@"Mail cancelled: you cancelled the operation and no email message was queued.");
            break;
        case MFMailComposeResultSaved:
            NSLog(@"Mail saved: you saved the email message in the drafts folder.");
            break;
        case MFMailComposeResultSent:
            NSLog(@"Mail send: the email message is queued in the outbox. It is ready to send.");
            break;
        case MFMailComposeResultFailed:
            NSLog(@"Mail failed: the email message was not saved or queued, possibly due to an error.");
        break;
        default:
            NSLog(@"Mail not sent.");
        break;
}

// Remove the mail view
[self dismissModalViewControllerAnimated:YES];

正在成功创建 - 我检查了模拟器文件。

- (void) exportData
{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES); 
    NSString *documentsDir = [paths objectAtIndex:0];
    NSString *root = [documentsDir stringByAppendingPathComponent:@"expenses.csv"];
    NSString *temp=@"Date,Purpose,Start Odometer,End Odometer, Total Driven, Fees, ";
    for(int i = 0; i < expenses.count; i++){
        VehicleExpense *tempExpense = [expenses objectAtIndex:i];
        temp = [temp stringByAppendingString:tempExpense.date];
        temp = [temp stringByAppendingString:@", "];
        temp = [temp stringByAppendingString:tempExpense.purpose];
        temp = [temp stringByAppendingString:@", "];
        temp = [temp stringByAppendingString:[NSString stringWithFormat: @"%.02f",tempExpense.start_mile]];
        temp = [temp stringByAppendingString:@", "];
        temp = [temp stringByAppendingString:[NSString stringWithFormat: @"%.02f",tempExpense.end_mile]];
        temp = [temp stringByAppendingString:@", "];
        temp = [temp stringByAppendingString:[NSString stringWithFormat: @"%.02f",tempExpense.distance]];
        temp = [temp stringByAppendingString:@", "];
        temp = [temp stringByAppendingString:[NSString stringWithFormat: @"%.02f",tempExpense.fees]];
        temp = [temp stringByAppendingString:@", "];
    }
    [temp writeToFile:root atomically:YES encoding:NSUTF8StringEncoding error:NULL];
    NSLog(@"got here in export data--- %@", documentsDir);

}

3 个答案:

答案 0 :(得分:11)

[mailer addAttachmentData:myData mimeType:@"text/csv" fileName:@"expenses.csv"];

修改 这是我在我的应用中使用的代码:

- (IBAction) ExportData:(id)sender
{       
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *filePath = [documentsDirectory stringByAppendingPathComponent:kExportFileName];

    self.timeRecords = [[NSMutableArray alloc] init];
    for (int i=0; i< [self.selectedTimeEntries count]; i++) 
        for (int j=0; j<[[self.selectedTimeEntries objectAtIndex:i] count]; j++) 
            if ([[self.selectedTimeEntries objectAtIndex:i] objectAtIndex:j] == [NSNumber numberWithBool:YES]) 
                [self.timeRecords addObject:[self timeEntriesForDay:[self.uniqueArray objectAtIndex:i] forIndex:j]];

    if( !([self.timeRecords count]!=0))
    {
        UIAlertView *alert=[[UIAlertView alloc] initWithTitle:@"There are no time entries selected!" message:@"Please select at least one time entry before proceeding" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [alert show];
        [alert release];        
        return;
    }
    NSMutableString *csvLine;
    NSError *err = nil;
    NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"yyyy-MM-dd"];
    NSString *dateString = nil;
    NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
    [numberFormatter setPositiveFormat:@"###0.##"];
    NSString *formattedNumberString = nil;

    if(![[NSFileManager defaultManager] fileExistsAtPath:filePath])        
    {
        [[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
    }

    for (timeEntries *timeEntry in self.timeRecords) {
        csvLine = [NSMutableString stringWithString:timeEntry.client];
        [csvLine appendString:@","];
        [csvLine appendString:timeEntry.category];
        [csvLine appendString:@","];
        [csvLine appendString:timeEntry.task];
        [csvLine appendString:@","];
        dateString = [dateFormatter stringFromDate:[NSDate dateWithTimeIntervalSince1970:timeEntry.date]];
        [csvLine appendString:dateString];
        [csvLine appendString:@","];
        formattedNumberString = [numberFormatter stringFromNumber:timeEntry.duration];
        [csvLine appendString:formattedNumberString];
        [csvLine appendString:@","];
        [csvLine appendString:timeEntry.description];
        [csvLine appendString:@"\n"];

        if([[NSFileManager defaultManager] fileExistsAtPath:filePath])        
        {     
            NSString *oldFile = [[NSString alloc] initWithContentsOfFile:filePath];
            [csvLine insertString:oldFile atIndex:0];
            BOOL success =[csvLine writeToFile:filePath atomically:NO encoding:NSUTF8StringEncoding error:&err];
            if(success){

            }
            [oldFile release];
        }
    } 
    if (!appDelegate.shouldSendCSV) {
    self.csvText = csvLine;
    }
    if([[NSFileManager defaultManager] fileExistsAtPath:filePath])        
    {
        [self emailExport:filePath];
    }   
    self.selectedTimeEntries =nil;
    self.navigationController.toolbarHidden = NO;
}


- (void)emailExport:(NSString *)filePath
{
    NSLog(@"Should send CSV = %@", [NSNumber numberWithBool:appDelegate.shouldSendCSV]);
    MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
    picker.mailComposeDelegate = self;

    // Set the subject of email
    [picker setSubject:@"My Billed Time Export"];

    // Add email addresses
    // Notice three sections: "to" "cc" and "bcc"   

    NSString *valueForEmail = [[NSUserDefaults standardUserDefaults] stringForKey:@"emailEntry"];
    NSString *valueForCCEmail = [[NSUserDefaults standardUserDefaults] stringForKey:@"ccEmailEntry"];
    if( valueForEmail == nil ||  [valueForEmail isEqualToString:@""])
    {
        UIAlertView *alert=[[UIAlertView alloc] initWithTitle:@"Please set an email address before sending a time entry!" message:@"You can change this address later from the settings menu of the application!" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [alert show];
        [alert release];        

        return;
    }
    else {
        [picker setToRecipients:[NSArray arrayWithObjects:valueForEmail, nil]];
    }

    if(valueForCCEmail != nil || ![valueForCCEmail isEqualToString:@""])
    {
        [picker setCcRecipients:[NSArray arrayWithObjects:valueForCCEmail, nil]];
    }

    // Fill out the email body text
    NSString *emailBody = @"My Billed Time Export File.";

    // This is not an HTML formatted email
    [picker setMessageBody:emailBody isHTML:NO];

    if (appDelegate.shouldSendCSV) {

    // Create NSData object from file
    NSData *exportFileData = [NSData dataWithContentsOfFile:filePath];

    // Attach image data to the email 
    [picker addAttachmentData:exportFileData mimeType:@"text/csv" fileName:@"MyFile.csv"];
    } else {
        [picker setMessageBody:self.csvText isHTML:NO];
    }
    // Show email view  
    [self presentModalViewController:picker animated:YES];

    // Release picker
    [picker release];
}

答案 1 :(得分:3)

Danut Pralea&#39; answer非常棒,但对于寻找简单方式 发送附件的人而言,代码似乎太长了以编程方式通过电子邮件发送

要点

我修剪了他的答案,只取出了重要的部分,并像这样重构了它:

MFMailComposeViewController *mailComposer = [[MFMailComposeViewController alloc] init];
mailComposer.mailComposeDelegate = self;

mailComposer.subject = @"Sample subject";

mailComposer.toRecipients = @[@"arthur@example.com", @"jeanne@example.com", ...];
mailComposer.ccRecipients = @[@"nero@example.com", @"mashu@example.com", ...];

[mailComposer setMessageBody:@"Sample body" isHTML:NO];

NSData *fileData = [NSData dataWithContentsOfFile:filePath];
[mailComposer addAttachmentData:fileData
                       mimeType:mimeType
                       fileName:fileName];

[self presentViewController:mailComposer animated:YES completion:nil];

这基本上是它的要点,这已经足够了。例如,如果您将此代码放在按钮的操作上,它将显示一个电子邮件撰写屏幕,其中预先填写了相应的字段,并将您要附加的文件附加到电子邮件中。

进一步阅读

<强>框架

MFMailComposeViewController位于MessageUI框架下,所以要使用它,导入(如果你还没有)框架就像这样:

#import <MessageUI/MessageUI.h>

邮件功能检查

现在,当您运行源代码并且尚未在设备上设置邮件帐户时(不确定模拟器上的行为是什么),此代码将使您的应用程序崩溃。似乎如果尚未设置邮件帐户,执行[[MFMailComposeViewController alloc] init]仍会导致mailComposer为零,causing the crash。正如链接问题中的answer所述:

  

您应该检查MFMailComposeViewController是否能够在发送

之前发送您的邮件

您可以使用canSendMail方法执行此操作,如下所示:

if (![MFMailComposeViewController canSendMail]) {
    [self openCannotSendMailDialog];
    return;
}

您可以在执行[[MFMailComposeViewController alloc] init]之前将其设置为正确,以便您可以立即通知用户。

处理无法发送邮件

如果canSendMail返回false,则根据Apple Dev Docs,这意味着该设备未配置为发送邮件。此could mean可能是用户尚未设置其邮件帐户。为了帮助用户,您可以提供open the Mail app并设置其帐户。你可以这样做:

NSURL *mailUrl = [NSURL URLWithString:@"message://"];
if ([[UIApplication sharedApplication] canOpenURL:mailUrl]) {
    [[UIApplication sharedApplication] openURL:mailUrl];
}

然后您可以像这样实施openCannotSendMailDialog

- (void)openCannotSendMailDialog
{
    UIAlertController *alert =
        [UIAlertController alertControllerWithTitle:@"Error"
                                            message:@"Cannot send mail."
                                preferredStyle:UIAlertControllerStyleAlert];

    NSURL *mailUrl = [NSURL URLWithString:@"message://"];
    if ([[UIApplication sharedApplication] canOpenURL:mailUrl]) {
        [alert addAction:
         [UIAlertAction actionWithTitle:@"Open Mail"
                                  style:UIAlertActionStyleDefault
                                handler:^(UIAlertAction * _Nonnull action) {
            [[UIApplication sharedApplication] openURL:mailUrl];
        }]];

        [alert addAction:
         [UIAlertAction actionWithTitle:@"Cancel"
                                  style:UIAlertActionStyleCancel
                                handler:^(UIAlertAction * _Nonnull action) {

        }]];

    } else {
        [alert addAction:
         [UIAlertAction actionWithTitle:@"OK"
                                  style:UIAlertActionStyleCancel
                                handler:^(UIAlertAction * _Nonnull action) {

        }]];

    }

    [self presentViewController:alert animated:YES completion:nil];
}

Mime类型

如果像我一样,您忘了/不确定使用哪个mimeTypehere是您可以使用的资源。最有可能的是,text/plain就足够了,如果您附加的文件只是纯文本,或image/jpeg / image/png用于图片。

<强>代表

正如您可能已经注意到的那样,Xcode会在以下行中向我们发出警告:

mailComposer.mailComposeDelegate = self; 

这是因为我们还没有将自己设置为符合适当的协议并实现其委托方法。如果您希望接收邮件是否已取消,保存,发送甚至发送失败,您需要将类设置为符合协议MFMailComposeViewControllerDelegate,并处理following events

  • MFMailComposeResultSent
  • MFMailComposeResultSaved
  • MFMailComposeResultCancelled
  • MFMailComposeResultFailed

根据Apple Dev Docs(强调我的):

  

邮件撰写视图控制器不会自动解除。当用户点击按钮发送电子邮件或取消界面时,邮件撰写视图控制器会调用其委托的mailComposeController:didFinishWithResult:error:方法。 您对该方法的实现必须明确忽略视图控制器

考虑到这一点,我们可以像这样实现委托方法:

- (void)mailComposeController:(MFMailComposeViewController *)controller
          didFinishWithResult:(MFMailComposeResult)result
                        error:(NSError *)error
{
    switch (result) {
        case MFMailComposeResultSent:
            // Mail was sent
            break;
        case MFMailComposeResultSaved:
            // Mail was saved as draft
            break;
        case MFMailComposeResultCancelled:
            // Mail composition was cancelled
            break;
        case MFMailComposeResultFailed:
            // 
            break;
        default:
            // 
            break;
    }

    // Dismiss the mail compose view controller.
    [controller dismissViewControllerAnimated:YES completion:nil];
}

<强>结论

最终代码可能如此:

- (void)openMailComposerWithSubject:(NSString *)subject
                   toRecipientArray:(NSArray *)toRecipientArray
                   ccRecipientArray:(NSArray *)ccRecipientArray
                        messageBody:(NSString *)messageBody
                  isMessageBodyHTML:(BOOL)isHTML
                attachingFileOnPath:(NSString)filePath
                           mimeType:(NSString *)mimeType
{
    if (![MFMailComposeViewController canSendMail]) {
        [self openCannotSendMailDialog];
        return;
    }

    MFMailComposeViewController *mailComposer = 
        [[MFMailComposeViewController alloc] init];
    mailComposer.mailComposeDelegate = self;

    mailComposer.subject = subject;

    mailComposer.toRecipients = toRecipientArray;
    mailComposer.ccRecipients = ccRecipientArray;

    [mailComposer setMessageBody:messageBody isHTML:isHTML];

    NSData *fileData = [NSData dataWithContentsOfFile:filePath];
    NSString *fileName = filePath.lastPathComponent;
    [mailComposer addAttachmentData:fileData
                           mimeType:mimeType
                           fileName:fileName];

    [self presentViewController:mailComposer animated:YES completion:nil];
}

- (void)openCannotSendMailDialog
{
    UIAlertController *alert =
        [UIAlertController alertControllerWithTitle:@"Error"
                                            message:@"Cannot send mail."
                                preferredStyle:UIAlertControllerStyleAlert];

    NSURL *mailUrl = [NSURL URLWithString:@"message://"];
    if ([[UIApplication sharedApplication] canOpenURL:mailUrl]) {
        [alert addAction:
         [UIAlertAction actionWithTitle:@"Open Mail"
                                  style:UIAlertActionStyleDefault
                                handler:^(UIAlertAction * _Nonnull action) {
            [[UIApplication sharedApplication] openURL:mailUrl];
        }]];

        [alert addAction:
         [UIAlertAction actionWithTitle:@"Cancel"
                                  style:UIAlertActionStyleCancel
                                handler:^(UIAlertAction * _Nonnull action) {

        }]];

    } else {
        [alert addAction:
         [UIAlertAction actionWithTitle:@"OK"
                                  style:UIAlertActionStyleCancel
                                handler:^(UIAlertAction * _Nonnull action) {

        }]];

    }

    [self presentViewController:alert animated:YES completion:nil];
}

- (void)mailComposeController:(MFMailComposeViewController *)controller
          didFinishWithResult:(MFMailComposeResult)result
                        error:(NSError *)error
{
    NSString *message;
    switch (result) {
        case MFMailComposeResultSent:
            message = @"Mail was sent.";
            break;
        case MFMailComposeResultSaved:
            message = @"Mail was saved as draft.";
            break;
        case MFMailComposeResultCancelled:
            message = @"Mail composition was cancelled.";
            break;
        case MFMailComposeResultFailed:
            message = @"Mail sending failed.";
            break;
        default:
            // 
            break;
    }

    // Dismiss the mail compose view controller.
    [controller dismissViewControllerAnimated:YES completion:^{
        if (message) {
            UIAlertController *alert =
                [UIAlertController alertControllerWithTitle:@"Confirmation"
                                                    message:message
                                        preferredStyle:UIAlertControllerStyleAlert];

            [alert addAction:
             [UIAlertAction actionWithTitle:@"OK"
                                      style:UIAlertActionStyleCancel
                                    handler:^(UIAlertAction * _Nonnull action) {

            }]];

            [self presentViewController:alert animated:YES completion:nil];
        }
    }];
}

按钮操作如下:

- (IBAction)mailButtonTapped:(id)sender
{
    NSString *reportFilePath = ...
    [self openMailComposerWithSubject:@"Report Files"
                     toRecipientArray:mainReportRecipientArray
                     ccRecipientArray:subReportRecipientArray
                          messageBody:@"I have attached report files in this email"
                    isMessageBodyHTML:NO
                  attachingFileOnPath:reportFilePath
                             mimeType:@"text/plain"];       
}

我在这里有点过分了,但你可以用一点点盐,拿走和使用我在这里发布的代码。当然需要根据您的要求进行调整,但这取决于您。 (我也从我的工作源代码中修改了这个答案,所以在某个地方可能会有错误,如果找到一个,请发表评论:))

答案 2 :(得分:0)

问题是我没有找到合适的文件位置。谢谢@EmilioPalesz。

这是我需要的代码:

 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES); 
NSString *documentsDir = [paths objectAtIndex:0];
NSString *root = [documentsDir stringByAppendingPathComponent:@"expenses.csv"]

NSData *myData = [NSData dataWithContentsOfFile:root];