1586
|
1 package luan.modules.mail;
|
|
2
|
|
3 import java.io.IOException;
|
|
4 import java.net.Socket;
|
|
5 import java.util.Map;
|
|
6 import java.util.LinkedHashMap;
|
|
7 import java.util.List;
|
1765
|
8 import javax.net.ssl.SSLSocket;
|
|
9 import goodjava.io.IoUtils;
|
1586
|
10 import goodjava.mail.Message;
|
|
11 import goodjava.mail.Smtp;
|
|
12 import goodjava.mail.MailException;
|
|
13 import luan.Luan;
|
|
14 import luan.LuanTable;
|
|
15 import luan.LuanException;
|
|
16
|
|
17
|
1589
|
18 public final class MailSender {
|
1586
|
19 private final String host;
|
|
20 private final int port;
|
|
21 private final String username;
|
|
22 private final String password;
|
|
23
|
1589
|
24 public MailSender(LuanTable paramsTbl) throws LuanException {
|
1586
|
25 Map<Object,Object> params = paramsTbl.asMap();
|
|
26
|
|
27 String host = getString(params,"host");
|
|
28 if( host==null )
|
|
29 throw new LuanException( "parameter 'host' is required" );
|
|
30 this.host = host;
|
|
31
|
|
32 Object port = params.remove("port");
|
|
33 if( port==null )
|
|
34 throw new LuanException( "parameter 'port' is required" );
|
|
35 if( !(port instanceof Number) )
|
|
36 throw new LuanException( "parameter 'port' must be an integer" );
|
|
37 Integer i = Luan.asInteger(port);
|
|
38 if( i == null )
|
|
39 throw new LuanException( "parameter 'port' must be an integer" );
|
|
40 this.port = i;
|
|
41
|
|
42 this.username = getString(params,"username");
|
|
43 this.password = getString(params,"password");
|
|
44 if( this.username!=null && this.password==null )
|
|
45 throw new LuanException( "password required with username" );
|
|
46 if( this.username==null && this.password!=null )
|
|
47 throw new LuanException( "username required with password" );
|
|
48
|
|
49 if( !params.isEmpty() )
|
|
50 throw new LuanException( "unrecognized parameters: "+params );
|
|
51 }
|
|
52
|
|
53 private static String getString(Map<Object,Object> params,String key) throws LuanException {
|
|
54 Object val = params.remove(key);
|
|
55 if( val!=null && !(val instanceof String) )
|
|
56 throw new LuanException( "parameter '"+key+"' must be a string" );
|
|
57 return (String)val;
|
|
58 }
|
|
59
|
|
60 private static Message message(LuanTable mailTbl) throws LuanException {
|
|
61 Map<Object,Object> mailParams = mailTbl.asMap();
|
|
62 Object body = mailParams.remove("body");
|
|
63 if( body == null )
|
|
64 throw new LuanException( "parameter 'body' is required" );
|
|
65 Map<String,String> headers = new LinkedHashMap<String,String>();
|
|
66 boolean hasContentType = false;
|
|
67 for( Map.Entry<Object,Object> entry : mailParams.entrySet() ) {
|
|
68 Object key = entry.getKey();
|
|
69 Object value = entry.getValue();
|
|
70 if( !(key instanceof String) )
|
|
71 throw new LuanException( "keys must be strings" );
|
|
72 if( !(value instanceof String) )
|
|
73 throw new LuanException( "value for '"+key+"' must be string" );
|
|
74 String name = (String)key;
|
|
75 headers.put(name,(String)value);
|
|
76 if( name.equalsIgnoreCase("content-type") )
|
|
77 hasContentType = true;
|
|
78 }
|
1587
|
79 if( body instanceof String ) {
|
|
80 if( !hasContentType )
|
|
81 headers.put("Content-Type","text/plain; charset=utf-8");
|
|
82 return new Message(headers,(String)body);
|
|
83 }
|
|
84 if( body instanceof byte[] ) {
|
1589
|
85 if( !hasContentType )
|
|
86 throw new LuanException("Content-Type required for binary body");
|
1587
|
87 return new Message(headers,(byte[])body);
|
|
88 }
|
|
89 if( body instanceof LuanTable ) {
|
1589
|
90 if( !hasContentType )
|
|
91 headers.put("Content-Type","multipart/mixed");
|
1587
|
92 LuanTable tbl = (LuanTable)body;
|
|
93 if( !tbl.isList() )
|
|
94 throw new LuanException( "body table must be a list" );
|
|
95 List list = tbl.asList();
|
|
96 Message[] msgs = new Message[list.size()];
|
|
97 for( int i=0; i<msgs.length; i++ ) {
|
|
98 Object obj = list.get(i);
|
|
99 if( !(obj instanceof LuanTable) )
|
|
100 throw new LuanException( "body table must be a list of part tables" );
|
|
101 msgs[i] = message((LuanTable)obj);
|
|
102 }
|
|
103 return new Message(headers,msgs);
|
|
104 }
|
|
105 throw new LuanException("body must be a string, binary, or list of part tables");
|
1586
|
106 }
|
|
107
|
|
108 public void send(LuanTable mailTbl) throws LuanException, IOException, MailException {
|
|
109 Message msg = message(mailTbl);
|
1765
|
110 Socket socket;
|
|
111 if( port == 465 ) {
|
|
112 SSLSocket sslSocket = (SSLSocket)IoUtils.getSSLSocketFactory().createSocket(host,port);
|
|
113 sslSocket.startHandshake();
|
|
114 socket = sslSocket;
|
|
115 } else {
|
|
116 socket = new Socket(host,port);
|
|
117 }
|
1586
|
118 Smtp smtp = new Smtp(socket);
|
|
119 if( username != null )
|
|
120 smtp.authenticate(username,password);
|
|
121 smtp.send(msg);
|
|
122 smtp.close();
|
|
123 }
|
|
124
|
|
125 }
|