In this example, Elvis is sending a GIF of his old Gumby friend. The attachment is encoded using the BASE64 algorithm.
In this example, we are sending as an attachment this image :

import java.io.*; import java.net.*; public class TestMailMIME { static int SMTPport = 25; static Socket socket; static DataInputStream in; static DataOutputStream out; static PrintStream prout; /* Name of file to be sent. */ String FileName = "gumby.gif"; public static void main(String s[]) { /* ** TestMailMIME [server] [recipient] */ TestMailMIME t = new TestMailMIME(); t.sendMail(s[0], s[1]); } public void sendMail(String mailServer, String recipient) { System.out.println("Send mail with attached file "); try { Socket s = new Socket(mailServer, 25); BufferedReader in = new BufferedReader (new InputStreamReader(s.getInputStream(), "8859_1")); BufferedWriter out = new BufferedWriter (new OutputStreamWriter(s.getOutputStream(), "8859_1")); String boundary = "DataSeparatorString"; // here you are supposed to send your username sendln(in, out, "HELO theWorld"); // warning : some mail server validate the sender address // in the MAIL FROM command, put your real address here sendln(in, out, "MAIL FROM: "); sendln(in, out, "RCPT TO: <" + recipient + ">" ); // to have more than one recipient, repeat // sendln(in, out, "RCPT TO: <" + recipient2 + ">" ); // sendln(in, out, "RCPT TO: <" + recipient3 + ">" ); // etc... // thanks to P-Y Colle for the tip! sendln(in, out, "DATA"); sendln(out, "MIME-Version: 1.0"); sendln(out, "Subject: remember me"); sendln(out, "From: Elvis Presley <Elvis.Presley@jailhouse.rock>"); sendln (out, "Content-Type: multipart/mixed; boundary=\"" + boundary +"\""); sendln(out, "\r\n--" + boundary); // Send the body sendln(out, "Content-Type: text/plain; charset=\"us-ascii\"\r\n"); sendln(out, "I'm alive. Help me!\r\n\r\n"); sendln(out, "\r\n--" + boundary ); // send the GIF sendln(out, "Content-Type:image/gif; name="+FileName); sendln (out, "Content-Disposition: attachment;filename=\""+FileName+"\""); sendln(out, "Content-transfer-encoding: base64\r\n"); MIMEBase64.encode(FileName, out); sendln(out, "\r\n--" + boundary); sendln(out, "\r\n\r\n--" + boundary + "--\r\n"); sendln(in, out,"."); sendln(in, out, "QUIT"); s.close(); } catch (Exception e) { e.printStackTrace(); } } public void sendln(BufferedReader in, BufferedWriter out, String s) { try { out.write(s + "\r\n"); out.flush(); // System.out.println(s); s = in.readLine(); // System.out.println(s); } catch (Exception e) { e.printStackTrace(); } } public void sendln(BufferedWriter out, String s) { try { out.write(s + "\r\n"); out.flush(); System.out.println(s); } catch (Exception e) { e.printStackTrace(); } } }
And the MIMEBase64 class
import java.io.*; public class MIMEBase64 { /* Base64 uses a 65 character subset of US-ASCII, allowing 6 bits for each character so the character "m" with a Base64 value of 38, when represented in binary form, is 100110. With a text string, let's say "men" is encoded this is what happens : The text string is converted into its US-ASCII value. The character "m" has the decimal value of 109 The character "e" has the decimal value of 101 The character "n" has the decimal value of 110 When converted to binary the string looks like this : m 01101101 e 01100101 n 01101110 These three "8-bits" are concatenated to make a 24 bit stream 011011010110010101101110 This 24 bit stream is then split up into 4 6-bit sections 011011 010110 010101 101110 We now have 4 values. These binary values are converted to decimal form 27 22 21 46 And the corresponding Base64 character are : b W V u The encoding is always on a three characters basis (to have a set of 4 Base64 characters). To encode one or two then, we use the special character "=" to pad until 4 base64 characters is reached. ex. encode "me" 01101101 01100101 0110110101100101 011011 010110 0101 111111 (AND to fill the missing bits) 011011 010110 010100 b W U b W U = ("=" is the padding character) so "bWU=" is the base64 equivalent. encode "m" 01101101 011011 01 111111 (AND to fill the missing bits) 011011 010000 b Q = = (two paddings are added) Finally, MIME specifies that lines are 76 characters wide maximum. */ static String BaseTable[] = { "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P", "Q","R","S","T","U","V","W","X","Y","Z","a","b","c","d","e","f", "g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v", "w","x","y","z","0","1","2","3","4","5","6","7","8","9","+","/" }; public static void encode(String filename, BufferedWriter out) { try { File f = new File(filename); FileInputStream fin = new FileInputStream(filename); // read the entire file into the byte array byte bytes[] = new byte[(int)(f.length())]; int n = fin.read(bytes); if (n < 1) return; // no bytes to encode!?! byte buf[] = new byte[4]; // array of base64 characters int n3byt = n / 3; // how 3 bytes groups? int nrest = n % 3; // the remaining bytes from the grouping int k = n3byt * 3; // we are doing 3 bytes at a time int linelength = 0; // current linelength int i = 0; // index // do the 3-bytes groups ... while ( i < k ) { buf[0] = (byte)(( bytes[i] & 0xFC) >> 2); buf[1] = (byte)(((bytes[i] & 0x03) << 4) | ((bytes[i+1] & 0xF0) >> 4)); buf[2] = (byte)(((bytes[i+1] & 0x0F) << 2) | ((bytes[i+2] & 0xC0) >> 6)); buf[3] = (byte)( bytes[i+2] & 0x3F); send(out, BaseTable[buf[0]]); send(out, BaseTable[buf[1]]); send(out, BaseTable[buf[2]]); send(out, BaseTable[buf[3]]); /* The above code can be written in more "optimized" way. Harder to understand but more compact. Thanks to J. Tordera for the tip! buf[0]= (byte)(b[i] >> 2); buf[1]= (byte)(((b[i] & 0x03) << 4)|(b[i+1]>> 4)); buf[2]= (byte)(((b[i+1] & 0x0F)<< 2)|(b[i+2]>> 6)); buf[3]= (byte)(b[i+2] & 0x3F); send(out,BaseTable[buf[0]]+BaseTable[buf[1]]+ BaseTable[buf[2]]+BaseTable[buf[3]]); */ if ((linelength += 4) >= 76) { send(out, "\r\n"); linelength = 0; } i += 3; } // deals with with the padding ... if (nrest==2) { // 2 bytes left buf[0] = (byte)(( bytes[k] & 0xFC) >> 2); buf[1] = (byte)(((bytes[k] & 0x03) << 4) | ((bytes[k+1] & 0xF0) >> 4)); buf[2] = (byte)(( bytes[k+1] & 0x0F) << 2); } else if (nrest==1) { // 1 byte left buf[0] = (byte)((bytes[k] & 0xFC) >> 2); buf[1] = (byte)((bytes[k] & 0x03) << 4); } if (nrest > 0) { // send the padding if ((linelength += 4) >= 76) send(out, "\r\n"); send(out, BaseTable[buf[0]]); send(out, BaseTable[buf[1]]); // Thanks to R. Claerman for the bug fix here! if (nrest==2) { send(out, BaseTable[buf[2]]); } else { send(out, "="); } send(out, "="); } out.flush(); } catch (Exception e) { e.printStackTrace(); } } public static void send(BufferedWriter out, String s) { try { out.write(s); System.out.print(s); } catch (Exception e) { e.printStackTrace(); } } }
If Elvis want to send a GIF and a text file about his Gumby old friend then he would change his sendMail() for something like this
... /* Name of files to be sent. */ String FileName1 = "gumby.gif"; String FileName2 = "gumby.txt"; ... public void sendMail(String mailServer, String recipient) { System.out.println("Send mail with attached file"); try { Socket s = new Socket(mailServer, 25); BufferedReader in = new BufferedReader (new InputStreamReader(s.getInputStream(), "8859_1")); BufferedWriter out = new BufferedWriter (new OutputStreamWriter(s.getOutputStream(), "8859_1")); String boundary = "DataSeparatorString"; // here you are supposed to send your username sendln(in, out, "HELO world"); sendln(in, out, "MAIL FROM: <real@gagnon.com>"); sendln(in, out, "RCPT TO: <" + recipient + ">" ); sendln(in, out, "DATA"); sendln(out, "MIME-Version: 1.0"); sendln(out, "Subject: remember me"); sendln(out, "From: Elvis Presley <Elvis.Presley@jailhouse.rock<"); sendln (out,"Content-Type: multipart/mixed; boundary=\"" + boundary +"\""); sendln(out, "\r\n--" + boundary); // send the GIF sendln(out, "Content-Type: text/plain; charset=\"us-ascii\"\r\n"); sendln(out, "I'm alive. Help me!\n\n"); sendln(out, "\r\n" + "--" + boundary ); sendln(out, "Content-Type:image/gif; name="+FileName1); sendln (out, "Content-Disposition: attachment;filename=\""+FileName1+"\""); sendln(out, "Content-transfer-encoding: base64\r\n"); MIMEBase64.encode(FileName1, out); sendln(out, "\r\n--" + boundary); // the text file sendln(out, "Content-Type: text/plain; name="+FileName2); sendln(out, "Content-Disposition: inline;filename=\""+FileName2+"\""); // to send the file as an attachment instead of "inline" use : // sendln // (out, "Content-Type: text/plain; name="+FileName2); // sendln // (out,"Content-Disposition: attachment;filename=\""+FileName2+"\""); sendln(out, "Content-Transfer-Encoding: base64\r\n"); MIMEBase64.encode(FileName2, out); sendln(out, "\r\n\r\n--" + boundary + "--\r\n"); // done sendln(in, out,"."); sendln(in, out, "QUIT"); s.close(); } catch (Exception e) { e.printStackTrace(); } } ...
Done! Haapy Coding!
Related posts:
Spring Cloud – Bootstrapping
A Custom Media Type for a Spring REST API
Converting a Stack Trace to a String in Java
HashMap trong Java hoạt động như thế nào?
Phương thức tham chiếu trong Java 8 – Method References
HttpAsyncClient Tutorial
Java Program to Solve the Fractional Knapsack Problem
Implementing a Binary Tree in Java
Tổng quan về ngôn ngữ lập trình java
Comparing Objects in Java
Tránh lỗi ConcurrentModificationException trong Java như thế nào?
Java Program to Implement Hash Tables with Linear Probing
Build a REST API with Spring and Java Config
Java Program to Implement Gift Wrapping Algorithm in Two Dimensions
Object Type Casting in Java
Biểu thức Lambda trong Java 8 – Lambda Expressions
Jackson – JsonMappingException (No serializer found for class)
Java Program to Implement Coppersmith Freivald’s Algorithm
Encode/Decode to/from Base64
Jackson – Unmarshall to Collection/Array
Guide to java.util.concurrent.Locks
So sánh HashMap và Hashtable trong Java
Java Web Services – Jersey JAX-RS – REST và sử dụng REST API testing tools với Postman
Spring AMQP in Reactive Applications
Converting a List to String in Java
Java Program to Implement Fenwick Tree
Spring’s RequestBody and ResponseBody Annotations
File Upload with Spring MVC
Java Program to Implement Gale Shapley Algorithm
Java Program to Implement Rope
Java Program to Implement Min Hash
Java Program to Repeatedly Search the Same Text (such as Bible by building a Data Structure)