R语言MailR发送邮件问题:单邮件多CSV附件而非多邮件
解决方案:单封邮件发送对应收件人的所有CSV附件
核心思路
- 先批量生成所有需要的CSV文件,同时记录每个文件对应的收件人邮箱
- 按收件人邮箱分组,收集每个收件人对应的所有本次新生成的CSV文件
- 对每个收件人仅发送一封包含其所有对应附件的邮件
修正后的代码
library(mailR) library(data.table) library(dplyr) parent_dir <- "location of the parent_dir path" df <- data.frame( city = c("New York", "Los Angeles", "New York", "Chicago", "Los Angeles", "Chicago"), year = c(2023, 2023, 2023, 2022, 2022, 2022), week = c(1, 2, 1, 1, 2, 2), value = c(100, 200, 150, 300, 250, 400), email = c("email1@example.com", "email1@example.com", "email3@example.com", "email4@example.com", "email3@example.com", "email4@example.com") ) # 初始化列表,存储邮箱与对应附件路径的映射 email_attachments <- list() # 批量生成CSV并记录附件与邮箱的关联 lapply(split(df, list(df$city, df$year, df$week), drop = TRUE), function(sub_df) { city <- unique(sub_df$city) year <- unique(sub_df$year) week <- unique(sub_df$week) # 创建层级文件夹(recursive=TRUE自动创建父级目录) city_folder <- paste0(parent_dir, city) year_folder <- file.path(city_folder, year) if (!dir.exists(city_folder)) dir.create(city_folder, recursive = TRUE) if (!dir.exists(year_folder)) dir.create(year_folder, recursive = TRUE) # 处理收件人邮箱(支持逗号分隔的多邮箱) sub_df$email <- strsplit(sub_df$email, ",") email_list <- unique(unlist(sub_df$email)) # 整理数据(移除不需要的列) remove_year_email <- sub_df %>% select(-c(year, email)) csv_file_path <- file.path(year_folder, paste0(city, " ", week, "-", year, ".csv")) # 仅生成不存在的文件(避免重复生成,确保仅本次新文件被作为附件) if (!file.exists(csv_file_path)) { fwrite(remove_year_email, csv_file_path, sep = ";") } # 将当前CSV路径关联到对应的每个邮箱 for (email in email_list) { if (is.null(email_attachments[[email]])) { email_attachments[[email]] <- c() } email_attachments[[email]] <- c(email_attachments[[email]], csv_file_path) } }) # 按邮箱分组,发送包含所有对应附件的单封邮件 for (email in names(email_attachments)) { send.mail( from = "sender", to = email, subject = "City files", body = "test", html = TRUE, smtp = list(host.name = "example", port = 1234, user.name = "example", passwd = "example", ssl = TRUE), authenticate = TRUE, send = TRUE, attach.files = email_attachments[[email]], debug = TRUE ) }
关键修改点
- 新增附件映射列表:用
email_attachments收集每个收件人对应的所有CSV路径,彻底解决"一个附件一封邮件"的问题 - 移除即时发送逻辑:将原代码中生成一个文件就发邮件的逻辑改为先记录所有附件,最后统一发送
- 文件存在检查:通过
!file.exists(csv_file_path)判断,仅生成新文件,确保附件只包含本次任务生成的内容,排除文件夹中已有文件 - 批量关联邮箱与附件:遍历每个子数据框对应的收件人,把CSV路径绑定到对应邮箱的列表中
内容的提问来源于stack exchange,提问作者MartijnB
相关产品推荐
相关产品推荐

