電子郵件早已成為工作生活中不可缺少的部分,每個工作的人都會有自己的私人郵箱或企業郵箱,用來協助我們處理生活事務以及實現工作中的交流。
今天主要通過簡單的示例,了解在Java中如何使用API來完成郵件的接收與發送。
通過該篇文章我們可以有如下收獲:
- 了解基于Java的電子郵件客戶端的實現方式
- 了解常見的郵箱如何集成
- 認識郵箱中的IMAP與POP協議
適用場景
郵件和短信很像,將信息發送到目的用戶,不需要用戶在線,基于郵件服務器,完成消息的存儲與轉發。一般公司都會有自己的企業郵箱,主要也是為了保證數據的安全性??赡苣闫綍r在注冊網站時,需要通過郵件來接收驗證消息完成認證流程;或者每天打開郵箱收到的各種訂閱消息等等。
- 基于電子郵件的通信與交流
- 接收驗證消息,實現用戶認證
- 發送郵件提供消息通知
說明
電子郵件在Internet上發送和接收的原理與我們通過郵局發信件非常相類似:首先要找到任何一個郵局,填寫郵件收件人姓名、地址等信息, 之后信件就會寄到收件人所在地的郵局,對方需要到相應的郵局才能取出信件。同樣,在發送電子郵件時,郵件是由郵件發送服務器發出, 根據收信人的地址匹配目的郵件接收服務器,收信人收取郵件需要訪問這個服務器才能取件。
郵件的發送與接收都需要基于特定的通信協議,發郵件時基于SMTP協議,收郵件時基于POP3、IMAP協議。
- SMTP
SMTP 的全稱是“Simple Mail Transfer Protocol”,即簡單郵件傳輸協議,是用于發送電子郵件的協議。它是一組用于從源地址到目的地址傳輸郵件的規范,通過它來控制郵件的中轉方式。SMTP 協議屬于 TCP/IP 協議簇,它幫助每臺計算機在發送或中轉信件時找到下一個目的地。SMTP 服務器就是遵循 SMTP 協議的發送郵件服務器。 - IMAP
IMAP(Internet Message Access Protocol)Internet郵件訪問協議,是用于接收電子郵件的協議。IMAP不用對服務器上面的郵件進行全部下載(根據實際需要進行下載),可以通過郵件客戶端對郵件進行操作;IMAP提供了WebMail與郵件客戶端之間的雙向通信,以及客戶端上的操作(如閱讀、刪除、移動郵件等)。 - POP3
POP3(Post Office Protocol version 3)郵局協議的第3個版本,同樣用于接收電子郵件的協議。POP3可以讓你下載郵件服務器上的郵件(下載所有未讀郵件),在郵件從服務器發送到電腦的同時刪除郵件服務器上的郵件(目前很多郵件服務器都支持“下載郵件,不刪除郵件,或者發出提醒”)。
POP允許電子郵件客戶端下載服務器上的郵件,但是您在電子郵件客戶端的操作(如:移動郵件、標記已讀等),這是不會反饋到服務器上的, 比如:您通過電子郵件客戶端收取了QQ郵箱中的3封郵件并移動到了其他文件夾,這些移動動作是不會反饋到服務器上的,也就是說,QQ郵箱服務器上的這些郵件是沒有同時被移動的。但是IMAP就不同了,電子郵件客戶端的操作都會反饋到服務器上,您對郵件進行的操作(如:移動郵件、標記已讀等),服務器上的郵件也會做相應的動作。也就是說,IMAP是“雙向”的。同時,IMAP可以只下載郵件的主題,只有當您真正需要的時候,才會下載郵件的所有內容。
如果感興趣可以深入了解這幾個協議的具體實現與規范,這里我們只用知道,與郵箱服務器對接時,是基于這幾個協議來實現通信,什么時候用什么協議即可。后面示例中會有用到。
郵箱與協議
如果要完成郵件的發送,我們需要知道用戶通過服務器將郵件發送給 誰 ,這里的用戶指的是發件方,需要明確我們的發件地址, 誰即對方的郵箱地址,郵箱地址主要郵3個部分組成, 用戶名 @ 郵件服務器域名 ,比如123456@qq.com,tom@gmail.com等等, 上面說到的服務器與域名對應。
在編寫示例前,需要先了解我們用到郵箱的一些信息,比如實現基于qq郵箱的郵件發送以及收取時,我們必須知道其郵箱服務器對應的協議服務地址以及端口, 下面是幾個常見的協議信息:
- 126郵箱
協議類型 | 協議功能 | 服務器地址 | 非SSL端口 | SSL端口號 |
---|---|---|---|---|
SMTP | 發送郵件 | smtp.126.com | 25 | 465、994 |
POP | 接收郵件 | pop.126.com | 110 | 995 |
IMAP | 接收郵件 | imap.126.com | 143 | 993 |
- 163郵箱
協議類型 | 協議功能 | 服務器地址 | 非SSL端口 | SSL端口號 |
---|---|---|---|---|
SMTP | 發送郵件 | smtp.163.com | 25 | 465 |
POP | 接收郵件 | pop.163.com | 110 | 995 |
IMAP | 接收郵件 | imap.163.com | 143 | 993 |
- QQ郵箱
協議類型 | 協議功能 | 服務器地址 | 非SSL端口 | SSL端口號 |
---|---|---|---|---|
SMTP | 發送郵件 | smtp.qq.com | 25 | 465、587 |
POP | 接收郵件 | pop.qq.com | 110 | 995 |
IMAP | 接收郵件 | imap.qq.com | 143 | 993 |
- Gmail郵箱
協議類型 | 協議功能 | 服務器地址 | 非SSL端口 | SSL端口號 |
---|---|---|---|---|
SMTP | 發送郵件 | smtp.gmail.com | 465、587 | |
POP | 接收郵件 | pop.gmail.com | 995 | |
IMAP | 接收郵件 | imap.gmail.com | 993 |
實例
在Java中我們可以基于JavaMail API實現郵件的發送與讀取,由于我使用的是JDK17,所以選用的是jakarta.mail.jar完成今天的示例。
在Spring中同樣提供了郵件的支持,我們可以在項目中通過引入spring-boot-starter-mail來集成,下面分別來看下如何實現郵件的收發功能。示例以QQ郵件為例,比如我的郵箱地址為409835152@qq.com,下面來看看具體實現過程
- 發送郵件
- 引入依賴
< dependency >
< groupId >org.springframework.boot< /groupId >
< artifactId >spring-boot-starter-mail< /artifactId >
< version >${spring-boot.version}< /version >
< /dependency >
- 添加application配置
spring:
mail:
host: smtp.qq.com
port: 25
protocol: smtp
username: 409835152@qq.com
password: '******'
這里主要配置了郵箱地址,和上面說到的協議類型、服務地址以及端口,最后還有一個密碼,注意這里不是郵箱登錄密碼,我們需要單獨申請,這個在各個郵箱中都有申請入口,比如qq郵箱中:
點擊“管理服務”在新的頁面中通過“生成授權碼”按流程申請即可,注意不要泄露!!!
- 編寫郵件發送服務
@Service
public class EmailQQService {
@Resource
private JavaMailSender javaMailSender;
@Resource
private MailProperties mailProperties;
public void sendEmail(Email email){
SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
simpleMailMessage.setFrom(mailProperties.getUsername()); //設置發送郵件賬號
simpleMailMessage.setTo(email.getTo()); //設置接收郵件的人,可以多個
simpleMailMessage.setSubject(email.getSubject()); //設置發送郵件的主題
simpleMailMessage.setText(email.getText()); //設置發送郵件的內容
javaMailSender.send(simpleMailMessage);
}
}
主要指定發送目標對象的郵箱地址,郵件主題以及郵件內容等即可??梢钥吹?,基于spring提供的工具,郵件的發送變得非常簡單。
- 郵件的接收
在Spring中沒有提供這樣的工具類,需要我們自己寫:
@Service
public class QqEmailService {
public List< Email > receiveEmail() throws MessagingException, IOException {
Properties properties = configProperties();
Store store = createStore( properties );
List< Email > emails = receive(store);
store.close();
return emails;
}
}
- 添加接收服務相關的配置,包括協議、服務地址、端口
private Properties configProperties(){
// 配置郵件服務器
Properties properties = new Properties();
properties.setProperty("mail.store.protocol", receiveMailProperties.getProtocol());
properties.setProperty("mail.imap.host", receiveMailProperties.getHost());
properties.setProperty("mail.imap.port", receiveMailProperties.getPort());
return properties;
}
- 創建Session與Store
private Store createStore(Properties properties) throws MessagingException {
// 創建Session實例對象
Session session = Session.getInstance( properties );
// 創建IMAP協議的Store對象
Store store = session.getStore("imap");
// 連接郵件服務器
store.connect(mailProperties.getUsername(), mailProperties.getPassword());
return store;
}
- 從服務器讀取郵件
private List< Email > receive(Store store) throws MessagingException, IOException {
// 獲得收件箱
Folder folder = store.getFolder("INBOX");
// 以讀寫模式打開收件箱
folder.open(Folder.READ_WRITE);
// 各狀態郵件數量
System.out.println(String.format("收件箱郵件總數:%s,其中,新郵件數:%s,未讀郵件數:%s,",folder.getMessageCount(), folder.getUnreadMessageCount(), folder.getNewMessageCount()));
// 獲得收件箱的郵件列表
Message[] messages = folder.getMessages(folder.getMessageCount()-5, folder.getMessageCount());
System.out.println("------------------------開始解析郵件----------------------------------");
List< Email > emailList = new ArrayList< >();
for (Message message : messages) {
Email email = new Email()
.setFrom(Arrays.stream(message.getFrom()).map(address - > ((InternetAddress)address).getAddress()).collect(Collectors.joining()))
.setSubject(message.getSubject())
.setContentType(message.getContentType())
.setSendDate(message.getSentDate())
.setReceiveDate(message.getReceivedDate());
System.out.println(String.format(" >> >> > 郵件來自:%s,主題:%s,接收時間:%s", email.getFrom(),
email.getSubject(),
DateFormatUtils.format(email.getReceiveDate(), DateFormatUtils.ISO_8601_EXTENDED_DATETIME_FORMAT.getPattern()))
);
email.setEmailContents(resolveMessage(message.getContentType(), message));
System.out.println(String.format("郵件內容:%s" , email.getEmailContents()));
emailList.add(email);
}
// 關閉資源
folder.close(false);
return emailList;
}
- 解析郵件內容,郵件除了文字,還有圖片,需要根據消息內容類型進行解析,當然發送消息的時候,同樣支持各種類型的消息,具體可以JavaMailSender的實現類
private List< EmailContent > resolveMessage(String contentType, Message message) throws MessagingException, IOException {
List< EmailContent > emailContents = new ArrayList< >();
resolveMessageContent( message.getContent(), message, emailContent- >{
emailContents.add(emailContent);
} );
// return content.toString();
return emailContents;
}
private void resolveMessageContent(Object content, Object parent, Consumer< EmailContent > emailContentConsumer) throws MessagingException, IOException {
if( content instanceof String ){
emailContentConsumer.accept( new EmailContent(EmailContent.Type.TEXT, (String) content) );
}else if( content instanceof MimeMultipart){
MimeMultipart multipart = (MimeMultipart) content;
int count = multipart.getCount(), index = -1;
while ( count > ++index ){// 0:純文本;1:html內容
BodyPart bodyPart = multipart.getBodyPart(index);
Object partContent = bodyPart.getContent();
resolveMessageContent( partContent, bodyPart, emailContentConsumer);
}
}else if( content instanceof BASE64DecoderStream){
File file = new File(((IMAPBodyPart) parent).getFileName());
((BASE64DecoderStream) content).transferTo( new FileOutputStream( file ) );
emailContentConsumer.accept( new EmailContent(EmailContent.Type.FILE, file.getAbsolutePath()) );
}else {
System.out.println(" >> >> >> >> >> >> >> >> 郵件內容類型: "+ content.getClass() );
emailContentConsumer.accept( new EmailContent(EmailContent.Type.TEXT, content.toString()) );
}
}
- 關閉store
store.close();
代碼有點多,但是流程不復雜且比較清晰。到這里一個簡單的針對qq郵箱的郵件發送與接收示例就完成了。不管是收郵件還是發郵件其關鍵點是:
- 郵件收發對應的協議類型、服務地址、服務端口
- 發送郵件用戶的郵箱地址與授權碼
- 目標郵箱地址
剩下的都是些簡單API調用的過程
-
服務器
+關注
關注
12文章
9332瀏覽量
86132 -
JAVA
+關注
關注
19文章
2976瀏覽量
105211 -
API
+關注
關注
2文章
1518瀏覽量
62448 -
郵件
+關注
關注
0文章
32瀏覽量
18823 -
傳輸協議
+關注
關注
0文章
79瀏覽量
11498
發布評論請先 登錄
相關推薦
用郵件來發送表單數據
LPSPI_MasterTransferEDMA 此 api可用于為dma或單獨的api發送和接收數據嗎?
使用Java API技巧分析
如何利用Stream API來優化Java代碼
基于Java的接口快速開發框架——magic-api
![基于<b class='flag-5'>Java</b>的接口快速開發框架——magic-<b class='flag-5'>api</b>](https://file1.elecfans.com/web2/M00/8D/22/wKgZomS3XFaAX-xeAAAHY1RBZAo088.jpg)
怎么用Python構建一個自動發送郵件的腳本
![怎么用Python構建一個自動<b class='flag-5'>發送</b><b class='flag-5'>郵件</b>的腳本](https://file1.elecfans.com/web2/M00/AB/6B/wKgZomUzc0yAKSlPAAGy2Ez7WR0403.jpg)
怎么用Python構建一個自動發送郵件的腳本
![怎么用Python構建一個自動<b class='flag-5'>發送</b><b class='flag-5'>郵件</b>的腳本](https://file1.elecfans.com/web2/M00/A9/AF/wKgaomUzc0yAK7-AAACWaJGi-Go841.jpg)
如何用Python批量定制化發送郵件
如何使用Python編寫腳本來自動發送郵件
Java集合API的改進介紹
![<b class='flag-5'>Java</b>集合<b class='flag-5'>API</b>的改進介紹](https://file1.elecfans.com/web2/M00/0D/0F/wKgaomc_9xKALcceAAAfW4_9zrE601.jpg)
評論