今天來介紹一下應用層的電子郵件服務,我們每天幾乎都在用,電子郵件(email)服務也是一種基於C/S模式的服務,它采用的是一種"存儲-轉發"的服務,是一種異步通信方式的服務,可以進行非實時通信.
整個電子郵件系統包括"用戶代理"(UA)和"消息傳輸代理"(MTA)兩大部分.
用戶代理(UA):為用戶提供操作界面,位於客戶端主機內.
信息傳輸代理(MTA):負責消息的傳輸,即所謂的"電子郵局",一般位於郵件服務器中.
收發電子郵件,需要遵守一些標准,常見的電子郵件協議有以下三個:
SMTP(簡單郵件傳輸協議):提供電子郵件的發送服務.端口號25.
POP3(郵局協議3):提供郵件接受的服務.端口號110;
IMAP(互聯網消息訪問協議):一種功能更強大,也更復雜的郵件接收的協議.改進了一些POP3的不足.端口號143.
SMTP只能基於文本進行傳輸,不能直接傳輸圖片,視頻等非文字的信息,但是配合一個叫做MIME的輔助協議可以將二進制編碼後再通過SMTP進行傳輸.
什麼是抄送?
假設A發郵件給了B,並且抄送給了C,那麼B可以看到,"哦,A給我發郵件了,但同時也發給了C,這郵件被C圍觀了".
什麼是暗送?
同樣,A發郵件給了B,並且暗送給了C,則B看不到郵件發給了C,"哦,A只給我發了郵件".
當發送方計算機和支持SMTP的郵件服務器建立連接後,把電子郵件准確無誤的發送到接收方的郵件服務器,如果跨多個網絡,SMTP可以跨網接力式傳輸.
注意:下面的不是指建立TCP連接,3個階段都是在TCP已建立好連接的基礎上進行的.
連接建立:TCP25號端口連接建立好以後,發件方調用SMTP客戶端發送HELO命令,和自己的域名,向收件方表明身份,如果通過驗證,收件方會返回"250 OK"的應答消息,這時就建立好了會話連接.
郵件傳輸:此階段發送方會使用多個命令,如用MAIL FROM指示發件人的郵箱地址,使用RCPT TO指示收件人的郵箱地址,此命令可以發送多次,如果服務器准備接受郵件則回復"250 OK",這時候,發送方就可以使用DATA命令發送郵件內容了,發送完畢後,服務器依然會返回"250 OK"表示一切順利.
連接釋放:沒有郵件傳輸時,發送方發送一條QUIT命令,請求關閉連接,服務器正常情況下會返回221的應答,表示接受關閉請求,釋放本次連接.
類比SMTP的作用,當接收方計算機與支持POP3協議的郵件服務器建立連接後,把存儲在該服務器上的郵件准確無誤的下載到收件方的主機.POP3是POP協議的第三個版本,解決了POP服務器上用戶閱讀了某郵件後即刪除該郵件的不足.
連接建立:建立好TCP110端口的連接後,進入身份驗證階段,收件方使用USER和PASS作為用戶名和密碼提供給服務器,完成身份驗證.
郵件接收:通過身份驗證後,進入事務處理階段,收件方可以發送POP3命令進行相應操作,郵件服務器會接受命令並作出響應.
連接釋放:操作完成,收件方發送QUIT命令,進入更新狀態,服務器確認關閉連接,並更新郵件存儲區.
最後在簡單介紹一下IMAP協議和MIME協議:
IMAP,提供了更加全面的功能,允許用戶像管理本地文件一樣自由地組織自己的郵箱,提供郵件摘要功能使用戶可有選擇地下載郵件,還提供了郵箱共享的功能
IMAP4能在三種模式下工作:離線模式、在線模式和斷線模式.
MIME是一種郵件擴展協議,通過對二進制文件進行編碼,實現了以普通文本格式郵件傳輸任意數據的功能
華麗的分割線之後,終於來到了我真正想寫的部分,以前學JavaEE的時候,接觸過javaMail發送郵件的功能,那時候對Email協議理解的很淺薄,很多知識點馬馬虎虎就過去了,看完了計算機網絡的電子郵件協議,又回去重新復習了一下JavaMail的相關內容,這裡做一個總結:
此session非彼session,這裡是javaMail中的一個類,Session類定義了基本的郵件會話,如果你得到了Session,表示你已經和郵件服務器連上了,完成了第一步,連接建立的階段,它的作用與JDBC的Connection有點相似.
通過查j2ee的文檔,可以發現這樣兩個方法,1.Session.getInstance(Properties prop); 2.Session.getInstance(Properties prop, Authenticator auth);,該方法返回一個Session,但需要兩個參數,先來看第一個參數Properties prop,這個參數需要指定兩個鍵值對,第一個是指定服務器主機名,第二個是指定是否需要認證,可以這樣得到:
Properties prop = new Properties();
prop.setProperty(“mail.host”, “smtp.qq.com”);//設置服務器主機名
prop.setProperty(“mail.smtp.auth”, “true”);//設置需要認證
第二個參數Authenticator是一個接口表示認證器,即校驗客戶端的身份。我們需要自己來實現這個接口,實現這個接口需要使用賬戶和密碼。
是抽象類Message的實現類,表示一個郵件對象,可以調用它的set*()方法,設置發件人,收件人,主題,正文等等...
是抽象類Address的實現類,是一個郵件地址類,用來設置郵件的發件地址,收件地址,等.如Address address=new InternetAddress("[email protected]");
這個類實現了發送消息的協議,即SMTP,在發送消息時,使用該類的一個抽象方法send(Message msg);方法是多樣的。當然,也可由Session獲得相應協議對應的Transport實例。並通過傳遞用戶名、密碼、郵件服務器主機名等參數建立與郵件服務器的連接,並使用sendMessage()方法將信息發送,最後關閉連接.
下面通過代碼實現發送郵件的過程:
/** * 第一種方式 * 使用Session.getInstance(Properties prop); * @throws Exception */ @Test public void sendMail1() throws Exception{ Properties prop=new Properties(); //指定一個默認的郵件服務器的主機名 prop.setProperty("mail.host", "smtp.163.com"); //設置smtp服務器需要進行驗證 prop.setProperty("mail.smtp.auth", "true"); //指定一個默認的消息訪問協議,Session的getTransport()返回實現此協議的Transport對象 prop.setProperty("mail.transport.protocol", "smtp"); //1.獲取連接 Session session=Session.getInstance(prop); //2.通過Session得到Transport對象, Transport ts=session.getTransport(); //如果不設置上面的prop的第三個鍵值對,可以使用下面這種方式 //Transport ts=session.getTransport("smtp"); //3.登錄郵件服務器,使用你的用戶名和密碼 ts.connect("smtp.163.com", "郵箱用戶名", "密碼"); //4.創建郵件內容Message MimeMessage msg=new MimeMessage(session); //設置發件人郵箱 msg.setFrom(new InternetAddress("[email protected]")); //指明收件人郵箱 msg.setRecipient(RecipientType.TO, new InternetAddress("[email protected]")); //指定郵件的標題 msg.setSubject("第一封簡單郵件"); //郵件的文本內容 msg.setContent("你好啊!", "text/html;charset=UTF-8"); //發送 ts.sendMessage(msg, msg.getAllRecipients()); //關閉連接 ts.close(); } /** * 第二種方式 * 使用Session.getInstance(Properties prop, Authenticator auth); */ @Test public void sendMail2() throws Exception{ /** * 1.得到session */ // Properties是Session的屬性對象,用於封裝針對SMTP的一些常用屬性 Properties props=new Properties(); //設置smtp服務器地址 props.setProperty("mail.host", "smtp.163.com"); //設置SMTP服務器是否需要用戶認證,默認為false,設為true props.setProperty("mail.smtp.auth", "true"); Authenticator auth=new Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { //注意:下面的登錄用戶名是@前邊的內容,如果你的賬號是[email protected],只需要輸入haha return new PasswordAuthentication("郵箱用戶名", "密碼"); } }; Session session = Session.getInstance(props,auth); /** * 2.創建MimeMessage */ MimeMessage msg=new MimeMessage(session); //設置發件人 msg.setFrom(new InternetAddress("[email protected]")); //設置收件人 msg.setRecipients(RecipientType.TO,"[email protected]"); //設置抄送 msg.setRecipients(RecipientType.CC,"[email protected]"); //設置主題 msg.setSubject("第二封簡單郵件"); //設置內容 msg.setContent("我是郵件","text/html;charset=utf-8"); /** * 3.發送 */ Transport.send(msg); }
以上只能完成文本的發送,如果想要發送圖片,視頻等多媒體的內容的話,就要考慮使用附件的方式.
當發送包含附件的郵件時,郵件體就為多部件的形式.上面在發送文本時,setContent()方法直接設置了正文內容.發送帶附件的郵件時,就需要設置正文內容為MimeMultiPart.
MimeMultiPart是一個部件的集合類,那麼什麼是部件呢?就是MimeBodyPart.他們之間的關系是這樣:
發送附件的具體代碼,也很簡單,這裡以附件是一張圖片為例,只需要把上面代碼中:
//設置內容 msg.setContent("我是郵件","text/html;charset=utf-8");
修改成下面這樣既可:
MimeMultipart list=new MimeMultipart(); //創建第一個MimebodtPart,為正文 MimeBodyPart part1=new MimeBodyPart(); part1.setContent("這是一封包含附件的垃圾郵箱","text/html;charset=utf-8"); list.addBodyPart(part1); //創建第二個MimebodtPart,為附件 MimeBodyPart part2=new MimeBodyPart(); //設置附件內容 part2.attachFile(new File("e:/照片/me.jpg")); //設置顯示的文件名 解決亂碼問題 part2.setFileName(MimeUtility.encodeText("哎喲,不錯哦.jpg")); list.addBodyPart(part2); msg.setContent(list);
javaMail的相關知識點,這篇博文,講得也很詳細,可以參考一下:http://www.cnblogs.com/xdp-gacl/p/4216311.html