背景:
每天早上需要发站会纪要,纪要内容为组员昨日的工作完成情况,工作完成情况需要从每个组员的exchange邮件中选择昨日发的日报邮件,提取信息,因组员很多,每天这种重复的复制粘贴操作很麻烦,就想到了用java写个程序来完成这个事。
概念:
exchage 与 outlook
Exchange是服务器端的软件,而Outlook是其客户端的软件。只是Outlook不仅仅可以作为Exchange的客户端,还可以接收其他支持Pop3等的邮件,当然,Exchange邮件接收方式也不仅仅局限于使用Outlook,你也可以使用Foxmail等其他软件,也可以通过Web方式使用OWA方式接收。(PS:在网上搜索API的时候千万不要搜outlook相关的api,因为是针对exchange服务端进行邮件的操作,而非outlook,虽然我们在客户端使用的outlook)
方法:
- 使用微软的第三方库OfficeDev/ews-java-api 来实现exchange邮件相关操作,Github:https://github.com/OfficeDev/ews-java-api
- 使用Jsoup库来实现对邮件里的html内容进行解析及替换,Github:https://github.com/jhy/jsoup
步骤:
- 连接exchange
- 查找自己邮件中的组员邮件,并保存
- 查找日报模板邮件,并在指定位置替换成组员邮件中的信息
- 发送邮件
代码:
- domain
package outlook.meeting
class UserStandMeeting {
static constraints = {
}
UserStandMeeting(List<String> yesterdayWork,List<String> todayWork,List<String> progress){
this.yesterdayWork = yesterdayWork
this.todayWork = todayWork
this.progress = progress
}
//成员姓名
String member
//昨日工作列表
List<String> yesterdayWork
//今日工作列表
List<String> todayWork
//昨日工作进度
List<String> progress
}
- main函数
package outlook.meeting
import microsoft.exchange.webservices.data.core.ExchangeService
import microsoft.exchange.webservices.data.core.PropertySet
import microsoft.exchange.webservices.data.core.enumeration.property.BasePropertySet
import microsoft.exchange.webservices.data.core.enumeration.property.WellKnownFolderName
import microsoft.exchange.webservices.data.core.enumeration.search.FolderTraversal
import microsoft.exchange.webservices.data.core.service.folder.Folder
import microsoft.exchange.webservices.data.core.service.item.EmailMessage
import microsoft.exchange.webservices.data.core.service.item.Item
import microsoft.exchange.webservices.data.core.service.schema.FolderSchema
import microsoft.exchange.webservices.data.credential.ExchangeCredentials
import microsoft.exchange.webservices.data.credential.WebCredentials
import microsoft.exchange.webservices.data.property.complex.MessageBody
import microsoft.exchange.webservices.data.search.FindFoldersResults
import microsoft.exchange.webservices.data.search.FolderView
import microsoft.exchange.webservices.data.search.ItemView
import microsoft.exchange.webservices.data.search.filter.SearchFilter
import org.apache.commons.lang3.StringUtils
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import org.jsoup.select.Elements
import java.text.SimpleDateFormat
class ReceiveMailByOnlineController {
//你的exchange账号
private static String EMAIL = "your exchange email"
//local地址:打开outlook->右上方文件-> office账户->local地址会显示在用户账户下方
private static String EMAIL_LOCAL = "your exchange local"
//你的exchange账号密码
private static String EMAIL_PASSWORD = "your exchange password"
//收件人的exchange账号
private static String EMAIL_TO = "to exchange email"
//组员成员
private static List<String> TEAM = Arrays.asList("xxx","xxx","xxx","xxx","xxx","xxx","xxx","xxx","xxx")
//筛选条件,筛选邮件时会根据这个字段来进行条件筛选
private static String FILTER_KEY = "日报"
//模板筛选条件,筛选模板邮件时会根据这个字段来进行条件筛选
private static String TEMPLATE_FOLDER_KEY = "站会纪要模板"
static void main(String[] args) {
//鉴权,获取连接
ExchangeService service = anthAccount()
//获取与保存数据
List<UserStandMeeting> userStandMeetingList = new ArrayList<UserStandMeeting>()
for(String member : TEAM){
getMemberContent(service,member,userStandMeetingList)
}
//获取模板,替换数据并发送
getTemplateContent(service,userStandMeetingList)
}
static ExchangeService anthAccount(){
ExchangeService service = new ExchangeService()
ExchangeCredentials credentials = new WebCredentials(EMAIL_LOCAL, EMAIL_PASSWORD)
service.setCredentials(credentials)
service.autodiscoverUrl(EMAIL)
return service
}
//查找组员日报邮件
static getMemberContent(ExchangeService service,String member,List<UserStandMeeting> userStandMeetingList){
//查找文件
FolderView view = new FolderView(10)
view.traversal = FolderTraversal.Deep
view.propertySet = new PropertySet(BasePropertySet.IdOnly)
view.propertySet.add(FolderSchema.DisplayName)
SearchFilter searchFilter = new SearchFilter.IsEqualTo(FolderSchema.DisplayName,member)
FindFoldersResults findFolderResults = service.findFolders(WellKnownFolderName.Root, searchFilter, view)
for(Folder item : findFolderResults.getFolders()){
for(Item i : item.findItems(new ItemView(10))){
if(i.getSubject().contains(FILTER_KEY)){
EmailMessage emailMessage = EmailMessage.bind(service, i.getId())
Document doc = Jsoup.parse(emailMessage.getBody().text,"GBK")
println("小组成员:" + member)
userStandMeetingList.push(getTableData(doc,member))
return
}
}
}
}
//获取模板邮件数据
static getTemplateContent(ExchangeService service,List<UserStandMeeting> userStandMeetingList){
//查找文件
FolderView view = new FolderView(1)
view.traversal = FolderTraversal.Deep
view.propertySet = new PropertySet(BasePropertySet.IdOnly)
view.propertySet.add(FolderSchema.DisplayName)
SearchFilter searchFilter = new SearchFilter.IsEqualTo(FolderSchema.DisplayName,TEMPLATE_FOLDER_KEY)
FindFoldersResults findFolderResults = service.findFolders(WellKnownFolderName.Root, searchFilter, view)
for(Folder item : findFolderResults.getFolders()){
for(Item i : item.findItems(new ItemView(1))){
EmailMessage emailMessage = EmailMessage.bind(service, i.getId())
Document doc = Jsoup.parse(emailMessage.getBody().text,"GBK")
String messageBody = replaceTableData(doc,userStandMeetingList)
sendMail(service,messageBody)
println("替换数据成功")
return
}
}
}
//解析日报信息
static getTableData(Document doc,String member){
Elements elements = doc.getElementsByTag("table")
UserStandMeeting userStandMeeting = new UserStandMeeting(new ArrayList<String>(),new ArrayList<String>(),new ArrayList<String>())
userStandMeeting.member = member
for(Element element:elements){
if(element.text() !=null && !"".equals(element.text())){
Elements es = element.select("tr")
for(Element tdelement:es){
Elements tdes = tdelement.select("td")
//只筛选需要的数据(今日工作)
//针对个别组员邮件格式不规范写的兼容代码
if(tdes.size() == 5 && !"工作事项".equals(tdes[0].text()) && !"xxx".equals(member) && !"xxx".equals(member) ||
(tdes.size() == 6 && !"工作事项".equals(tdes[0].text()) && "xxx".equals(member)) ||
(tdes.size() == 6 && !"工作事项".equals(tdes[0].text()) && "xxx".equals(member))) {
if(StringUtils.isNotBlank(tdes[0].text())){
userStandMeeting.yesterdayWork.push(tdes[0].text())
userStandMeeting.progress.push(tdes[2].text())
}
}
//只筛选需要的数据(昨日工作)
//针对个别组员邮件格式不规范写的兼容代码
if((tdes.size() == 4 && !"工作事项".equals(tdes[0].text()) && !"xxx".equals(member)) && !"xxx".equals(member) ||
(tdes.size() == 5 && !"工作事项".equals(tdes[0].text()) && "xxx".equals(member)) ||
(tdes.size() == 5 && !"工作事项".equals(tdes[0].text()) && "xxx".equals(member))){
if(StringUtils.isNotBlank(tdes[0].text())){
userStandMeeting.todayWork.push(tdes[0].text())
}
}
}
}
}
return userStandMeeting
}
//替换模板数据
static replaceTableData(Document doc,List<UserStandMeeting> userStandMeetingList){
Elements elements = doc.getElementsByTag("table")
for(Element element:elements){
if(element.text() !=null && !"".equals(element.text())){
Elements es = element.select("tr")
for(Element tdelement:es){
Elements tdes = tdelement.select("td")
if(tdes.size() == 7 && tdes[0].text() != "姓名"){
for(UserStandMeeting u : userStandMeetingList){
if(u.member.equals(tdes[0].text())){
String yesterdayWork = ""
for(String s : u.yesterdayWork){
yesterdayWork = yesterdayWork + s + "<br>"
}
tdes[1].html(yesterdayWork)
String progress = ""
for(String s : u.progress){
progress = progress + s + "<br>"
}
tdes[2].html(progress)
String todayWork = ""
for(String s : u.todayWork){
todayWork = todayWork + s + "<br>"
}
tdes[3].html(todayWork)
}
}
}
}
}
}
return new String(doc.html().getBytes("UTF-8"),"UTF-8")
}
//发送邮件
static sendMail(ExchangeService service,String messageBody){
EmailMessage email = new EmailMessage(service)
email.toRecipients.add(EMAIL_TO)
email.subject = formatDate()
email.body = new MessageBody(messageBody)
email.send()
println("send success")
}
//时间格式化
static formatDate(){
SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-DD")
return sdf.format(new Date()) + "站会纪要"
}
}