דוגמת JavaMail – שליחת מייל ב־Java באמצעות SMTP

היום נסתכל על דוגמת JavaMail לשליחת אימייל בתוכניות Java. שליחת אימיילים היא אחת מהמשימות הנפוצות ביישומים בחיים האמיתיים ולכן Java מספקת JavaMail API חזקה שאפשר להשתמש בה כדי לשלוח אימיילים באמצעות שרת SMTP. JavaMail API תומך באימות גם ב־TLS וגם ב־SSL עבור שליחת אימיילים.

דוגמת JavaMail

היום נלמד כיצד להשתמש ב־JavaMail API כדי לשלוח אימיילים באמצעות שרת SMTP ללא אימות, עם אימות TLS ו־SSL, וכיצד לשלוח קבצים מצורפים ולהוסיף ולהשתמש בתמונות בגוף האימייל. לצורך אימות TLS ו־SSL, אני משתמש בשרת SMTP של GMail מכיוון שהוא תומך בשניהם. באפשרותך גם לבחור להשתמש ב־שרת אימייל של Java בהתאם לצרכי הפרוייקט שלך. JavaMail API אינה חלק מסטנדרט JDK התקני, כך שתצטרך להוריד אותו מהאתר הרשמי שלו, כלומר דף הבית של JavaMail. הורד את הגרסה האחרונה של המימוש המפורסם של JavaMail וכלול אותו בנתיב הבנייה של הפרוייקט שלך. שם הקובץ יהיה javax.mail.jar. אם אתה משתמש בפרוייקט מבוסס Maven, פשוט הוסף את התלות הבאה בפרוייקט שלך.

<dependency>
	<groupId>com.sun.mail</groupId>
	<artifactId>javax.mail</artifactId>
	<version>1.5.5</version>
</dependency>

התוכנית ב־Java לשליחת אימייל כוללת את השלבים הבאים:

  1. יצירת אובייקט javax.mail.Session
  2. יצירת אובייקט javax.mail.internet.MimeMessage, עלינו להגדיר מאפיינים שונים באובייקט זה כגון כתובת דוא"ל של הנמען, נושא הודעת הדוא"ל, דוא"ל לתגובה, גוף ההודעה, קבצים מצורפים וכו '
  3. שימוש ב- javax.mail.Transport לשליחת הודעת הדוא"ל.

הלוגיקה ליצירת הסשן משתנה בהתאם לסוג שרת SMTP, לדוגמה אם השרת SMTP אינו דורש אימות נוכל ליצור את אובייקט הסשן עם תכונות פשוטות, בעוד שאם הוא דורש אימות TLS או SSL, אזי הלוגיקה ליצירה תהיה שונה. לכן אני אצור מחלקת יוטיליטי עם מספר שיטות יוטיליטיות לשליחת דואר אלקטרוני ואז אשתמש בשיטת היוטיליטי הזו עם שרתי SMTP שונים.

דוגמה לתכנית JavaMail

מחלקת ה-EmailUtil שלנו שיש בה שיטה יחידה לשליחת דואר אלקטרוני נראית כך, היא מצריכה את javax.mail.Session וכמה שדות נדרשים נוספים כארגומנטים. כדי לשמור על פשטות, חלק מהארגומנטים מוקשים, אך תוכלו להרחיב את השיטה כדי להעביר אותם או לקרוא אותם מקבצי תצורה מסוימים.

package com.journaldev.mail;

import java.io.UnsupportedEncodingException;
import java.util.Date;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

public class EmailUtil {

	/**
	 * Utility method to send simple HTML email
	 * @param session
	 * @param toEmail
	 * @param subject
	 * @param body
	 */
	public static void sendEmail(Session session, String toEmail, String subject, String body){
		try
	    {
	      MimeMessage msg = new MimeMessage(session);
	      //הגדרת כותרות הודעה
	      msg.addHeader("Content-type", "text/HTML; charset=UTF-8");
	      msg.addHeader("format", "flowed");
	      msg.addHeader("Content-Transfer-Encoding", "8bit");

	      msg.setFrom(new InternetAddress("[email protected]", "NoReply-JD"));

	      msg.setReplyTo(InternetAddress.parse("[email protected]", false));

	      msg.setSubject(subject, "UTF-8");

	      msg.setText(body, "UTF-8");

	      msg.setSentDate(new Date());

	      msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(toEmail, false));
	      System.out.println("Message is ready");
    	  Transport.send(msg);  

	      System.out.println("EMail Sent Successfully!!");
	    }
	    catch (Exception e) {
	      e.printStackTrace();
	    }
	}
}

שימו לב שאני מגדיר כמה מאפייני כותרת ב-MimeMessage, הם משמשים על ידי תוכנות הדוא"ל לעיבוד והצגת ההודעה בצורה תקנית. שאר התוכנית היא פשוטה ומובנית מאליה. עכשיו בואו ניצור את התוכנית שלנו לשליחת דואר אלקטרוני בלי אימות.

שליחת מייל ב-Java באמצעות SMTP ללא אימות

package com.journaldev.mail;

import java.util.Properties;

import javax.mail.Session;

public class SimpleEmail {
	
	public static void main(String[] args) {
		
	    System.out.println("SimpleEmail Start");
		
	    String smtpHostServer = "smtp.example.com";
	    String emailID = "[email protected]";
	    
	    Properties props = System.getProperties();

	    props.put("mail.smtp.host", smtpHostServer);

	    Session session = Session.getInstance(props, null);
	    
	    EmailUtil.sendEmail(session, emailID,"SimpleEmail Testing Subject", "SimpleEmail Testing Body");
	}

}

שים לב שאני משתמש ב־Session.getInstance() כדי לקבל את אובייקט ה־Session על ידי מעבר של אובייקט ה־Properties. עלינו להגדיר את המאפיין mail.smtp.host עם שרת ה-SMTP. אם שרת ה-SMTP לא פועל בפורט ברירת המחדל (25), אז תצטרך גם להגדיר את המאפיין mail.smtp.port. פשוט הפעל את התוכנית עם שרת SMTP ללא אימות שלך ועל ידי הגדרת כתובת הדוא"ל של הנמען ככתובת הדוא"ל שלך ותקבל את הדוא"ל מיד. התוכנית פשוטה להבנה ועובדת היטב, אך בחיים האמיתיים רוב שרתי ה-SMTP משתמשים בסוגים שונים של אימות כגון אימות TLS או SSL. לכן כעת נראה כיצד ליצור אובייקט Session עבור פרוטוקולי האימות הללו.

שליחת אימייל ב-Java SMTP עם אימות TLS

package com.journaldev.mail;

import java.util.Properties;

import javax.mail.Authenticator;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;

public class TLSEmail {

	/**
	   Outgoing Mail (SMTP) Server
	   requires TLS or SSL: smtp.gmail.com (use authentication)
	   Use Authentication: Yes
	   Port for TLS/STARTTLS: 587
	 */
	public static void main(String[] args) {
		final String fromEmail = "[email protected]"; //requires valid gmail id
		final String password = "mypassword"; // correct password for gmail id
		final String toEmail = "[email protected]"; // can be any email id 
		
		System.out.println("TLSEmail Start");
		Properties props = new Properties();
		props.put("mail.smtp.host", "smtp.gmail.com"); //SMTP Host
		props.put("mail.smtp.port", "587"); //TLS Port
		props.put("mail.smtp.auth", "true"); //enable authentication
		props.put("mail.smtp.starttls.enable", "true"); //enable STARTTLS
		
                //יצירת אובייקט Authenticator כדי להעביר בארגומנט של Session.getInstance
		Authenticator auth = new Authenticator() {
			//דריסת השיטה getPasswordAuthentication
			protected PasswordAuthentication getPasswordAuthentication() {
				return new PasswordAuthentication(fromEmail, password);
			}
		};
		Session session = Session.getInstance(props, auth);
		
		EmailUtil.sendEmail(session, toEmail,"TLSEmail Testing Subject", "TLSEmail Testing Body");
		
	}

	
}

מאחר ואני משתמש בשרת SMTP של Gmail שנגיש לכולם, אתה יכול להגדיר את המשתנים הנכונים בתוכנית למעלה ולהריץ אותה לבד. תאמין לי, זה עובד! 🙂

דוגמה לשימוש ב-Java SMTP עם אימות SSL

package com.journaldev.mail;

import java.util.Properties;

import javax.mail.Authenticator;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;

public class SSLEmail {

	/**
	   Outgoing Mail (SMTP) Server
	   requires TLS or SSL: smtp.gmail.com (use authentication)
	   Use Authentication: Yes
	   Port for SSL: 465
	 */
	public static void main(String[] args) {
		final String fromEmail = "[email protected]"; //requires valid gmail id
		final String password = "mypassword"; // correct password for gmail id
		final String toEmail = "[email protected]"; // can be any email id 
		
		System.out.println("SSLEmail Start");
		Properties props = new Properties();
		props.put("mail.smtp.host", "smtp.gmail.com"); //SMTP Host
		props.put("mail.smtp.socketFactory.port", "465"); //SSL Port
		props.put("mail.smtp.socketFactory.class",
				"javax.net.ssl.SSLSocketFactory"); //SSL Factory Class
		props.put("mail.smtp.auth", "true"); //Enabling SMTP Authentication
		props.put("mail.smtp.port", "465"); //SMTP Port
		
		Authenticator auth = new Authenticator() {
			// דריסת הפעולה getPasswordAuthentication
			protected PasswordAuthentication getPasswordAuthentication() {
				return new PasswordAuthentication(fromEmail, password);
			}
		};
		
		Session session = Session.getDefaultInstance(props, auth);
		System.out.println("Session created");
	        EmailUtil.sendEmail(session, toEmail,"SSLEmail Testing Subject", "SSLEmail Testing Body");

	        EmailUtil.sendAttachmentEmail(session, toEmail,"SSLEmail Testing Subject with Attachment", "SSLEmail Testing Body with Attachment");

	        EmailUtil.sendImageEmail(session, toEmail,"SSLEmail Testing Subject with Image", "SSLEmail Testing Body with Image");

	}

}

התוכנית דומה בערך לאימות TLS, רק מספר נכסים שונים. כפי שניתן לראות, אני קורא לכמה פעולות אחרות מתוך מחלקת EmailUtil כדי לשלוח קובץ מצורף ותמונה באימייל, אך לא הגדרתי אותם עדיין. למעשה, אני שמרתי אותם כדי להציג אותם מאוחר יותר ולהשאיר זאת פשוטה בהתחלת המדריך.

דוגמה ל-JavaMail – שליחת אימייל ב-Java עם קובץ מצורף

כדי לשלוח קובץ כמצורף, עלינו ליצור אובייקט של javax.mail.internet.MimeBodyPart ו-javax.mail.internet.MimeMultipart. ראשית, נוסיף את חלק הגוף עבור ההודעת טקסט באימייל ואז נשתמש ב-FileDataSource כדי לצרף את הקובץ בחלק השני של גוף ה-Multipart. השיטה נראית כמו בהמשך.

/**
 * Utility method to send email with attachment
 * @param session
 * @param toEmail
 * @param subject
 * @param body
 */
public static void sendAttachmentEmail(Session session, String toEmail, String subject, String body){
	try{
         MimeMessage msg = new MimeMessage(session);
         msg.addHeader("Content-type", "text/HTML; charset=UTF-8");
	     msg.addHeader("format", "flowed");
	     msg.addHeader("Content-Transfer-Encoding", "8bit");
	      
	     msg.setFrom(new InternetAddress("[email protected]", "NoReply-JD"));

	     msg.setReplyTo(InternetAddress.parse("[email protected]", false));

	     msg.setSubject(subject, "UTF-8");

	     msg.setSentDate(new Date());

	     msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(toEmail, false));
	      
         // יצירת חלק גוף ההודעה
         BodyPart messageBodyPart = new MimeBodyPart();

         // מילוי ההודעה
         messageBodyPart.setText(body);
         
         // יצירת הודעת Multipart עבור המצורף
         Multipart multipart = new MimeMultipart();

         // הגדרת חלק הודעת הטקסט
         multipart.addBodyPart(messageBodyPart);

         // החלק השני הוא המצורף
         messageBodyPart = new MimeBodyPart();
         String filename = "abc.txt";
         DataSource source = new FileDataSource(filename);
         messageBodyPart.setDataHandler(new DataHandler(source));
         messageBodyPart.setFileName(filename);
         multipart.addBodyPart(messageBodyPart);

         // שליחת חלקי ההודעה השלמים
         msg.setContent(multipart);

         // שליחת ההודעה
         Transport.send(msg);
         System.out.println("EMail Sent Successfully with attachment!!");
      }catch (MessagingException e) {
         e.printStackTrace();
      } catch (UnsupportedEncodingException e) {
		 e.printStackTrace();
	}
}

התוכנית עשויה להיראות מורכבת מראש, אך היא פשוטה, פשוט יצור חלק גוף עבור הודעת טקסט וחלק גוף נוסף עבור הצרף ואז להוסיף אותם ל- multipart. ניתן להרחיב את השיטה הזו כדי לצרף קבצים מרובים גם.

דוגמת JavaMail – שליחת מייל ב-Java עם תמונה

מאחר שניתן ליצור הודעת גוף HTML, אם הקובץ התמונה ממוקם במיקום שרת מסוים, ניתן להשתמש ברכיב img כדי להציג אותם בהודעה. אך לעיתים קרובות רוצים לצרף את התמונה בדוא"ל ולאחר מכן להשתמש בה בגוף הדוא"ל עצמו. כנראה שראית כמה דואר אלקטרוני שכולל קבצי תמונה מצורפים ונעשה בהם שימוש בהודעת הדוא"ל. התרמה היא לצרף את קובץ התמונה כמו כל צרוף אחר ולהגדיר את הכותרת Content-ID לקובץ התמונה ולאחר מכן להשתמש באותו זיהוי תוכן בגוף הודעת הדוא"ל עם <img src='cid:image_id'>.

/**
 * Utility method to send image in email body
 * @param session
 * @param toEmail
 * @param subject
 * @param body
 */
public static void sendImageEmail(Session session, String toEmail, String subject, String body){
	try{
         MimeMessage msg = new MimeMessage(session);
         msg.addHeader("Content-type", "text/HTML; charset=UTF-8");
	     msg.addHeader("format", "flowed");
	     msg.addHeader("Content-Transfer-Encoding", "8bit");
	      
	     msg.setFrom(new InternetAddress("[email protected]", "NoReply-JD"));

	     msg.setReplyTo(InternetAddress.parse("[email protected]", false));

	     msg.setSubject(subject, "UTF-8");

	     msg.setSentDate(new Date());

	     msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(toEmail, false));
	      
         // צור את חלק גוף ההודעה
         BodyPart messageBodyPart = new MimeBodyPart();

         messageBodyPart.setText(body);
         
         // צור הודעה מרובת חלקים עבור צרף
         Multipart multipart = new MimeMultipart();

         // הגדר חלק טקסט
         multipart.addBodyPart(messageBodyPart);

         // החלק השני הוא צרוף תמונה
         messageBodyPart = new MimeBodyPart();
         String filename = "image.png";
         DataSource source = new FileDataSource(filename);
         messageBodyPart.setDataHandler(new DataHandler(source));
         messageBodyPart.setFileName(filename);
         // התרסיס הוא להוסיף את כותרת ה- content-id כאן
         messageBodyPart.setHeader("Content-ID", "image_id");
         multipart.addBodyPart(messageBodyPart);

         // חלק שלישי לתצוגת התמונה בגוף הדוא"ל
         messageBodyPart = new MimeBodyPart();
         messageBodyPart.setContent("

Attached Image

" + "", "text/html"); multipart.addBodyPart(messageBodyPart); // הגדר את ההודעה מרובת החלקים להודעת הדוא"ל msg.setContent(multipart); // שלח הודעה Transport.send(msg); System.out.println("EMail Sent Successfully with image!!"); }catch (MessagingException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } }

טיפים לפיתרון בעיות ב- JavaMail API

  1. java.net.UnknownHostException מתרחש כאשר המערכת שלך לא מצליחה לפתור את כתובת ה-IP של שרת SMTP, זה עשוי להיות שגוי או לא נגיש מהרשת שלך. לדוגמה, שרת SMTP של GMail הוא smtp.gmail.com ואם אני משתמש ב- smtp.google.com, אני אקבל את החריגה הזו. אם השם המארח נכון, נסה לבדוק את השרת דרך פקודת שורת הפקודה כדי לוודא שהוא נגיש מהמערכת שלך.

    pankaj@Pankaj:~/CODE$ ping smtp.gmail.com
    PING gmail-smtp-msa.l.google.com (74.125.129.108): 56 data bytes
    64 bytes from 74.125.129.108: icmp_seq=0 ttl=46 time=38.308 ms
    64 bytes from 74.125.129.108: icmp_seq=1 ttl=46 time=42.247 ms
    64 bytes from 74.125.129.108: icmp_seq=2 ttl=46 time=38.164 ms
    64 bytes from 74.125.129.108: icmp_seq=3 ttl=46 time=53.153 ms
    
  2. אם התוכנית שלך תקועה בקריאת שיטת Transport send(), בדוק שפורט SMTP הוא נכון. אם זה נכון, השתמש ב־telnet כדי לוודא שהוא נגיש מהמחשב שלך. תקבל פלט דומה למה שבתמצאות מטה.

    pankaj@Pankaj:~/CODE$ telnet smtp.gmail.com 587
    Trying 2607:f8b0:400e:c02::6d...
    Connected to gmail-smtp-msa.l.google.com.
    Escape character is '^]'.
    220 mx.google.com ESMTP sx8sm78485186pab.5 - gsmtp
    HELO
    250 mx.google.com at your service
    

זהו הכול בשביל דוגמה ב־JavaMail לשליחת דואר ב־Java באמצעות שרת SMTP עם פרוטוקולי אימות שונים, קבצים מצורפים ותמונות. אני מקווה שזה יפתור את כל צרכי השליחת דואר בתוכניות Java שלך.

Source:
https://www.digitalocean.com/community/tutorials/javamail-example-send-mail-in-java-smtp