1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.mail.javamail;
18
19 import java.io.InputStream;
20 import java.util.ArrayList;
21 import java.util.Date;
22 import java.util.LinkedHashMap;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Properties;
26 import javax.activation.FileTypeMap;
27 import javax.mail.AuthenticationFailedException;
28 import javax.mail.MessagingException;
29 import javax.mail.NoSuchProviderException;
30 import javax.mail.Session;
31 import javax.mail.Transport;
32 import javax.mail.internet.MimeMessage;
33
34 import org.springframework.mail.MailAuthenticationException;
35 import org.springframework.mail.MailException;
36 import org.springframework.mail.MailParseException;
37 import org.springframework.mail.MailPreparationException;
38 import org.springframework.mail.MailSendException;
39 import org.springframework.mail.SimpleMailMessage;
40 import org.springframework.util.Assert;
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68 public class JavaMailSenderImpl implements JavaMailSender {
69
70
71 public static final String DEFAULT_PROTOCOL = "smtp";
72
73
74 public static final int DEFAULT_PORT = -1;
75
76 private static final String HEADER_MESSAGE_ID = "Message-ID";
77
78
79 private Properties javaMailProperties = new Properties();
80
81 private Session session;
82
83 private String protocol;
84
85 private String host;
86
87 private int port = DEFAULT_PORT;
88
89 private String username;
90
91 private String password;
92
93 private String defaultEncoding;
94
95 private FileTypeMap defaultFileTypeMap;
96
97
98
99
100
101
102
103 public JavaMailSenderImpl() {
104 ConfigurableMimeFileTypeMap fileTypeMap = new ConfigurableMimeFileTypeMap();
105 fileTypeMap.afterPropertiesSet();
106 this.defaultFileTypeMap = fileTypeMap;
107 }
108
109
110
111
112
113
114
115
116
117 public void setJavaMailProperties(Properties javaMailProperties) {
118 this.javaMailProperties = javaMailProperties;
119 synchronized (this) {
120 this.session = null;
121 }
122 }
123
124
125
126
127
128
129
130 public Properties getJavaMailProperties() {
131 return this.javaMailProperties;
132 }
133
134
135
136
137
138
139
140
141
142 public synchronized void setSession(Session session) {
143 Assert.notNull(session, "Session must not be null");
144 this.session = session;
145 }
146
147
148
149
150
151 public synchronized Session getSession() {
152 if (this.session == null) {
153 this.session = Session.getInstance(this.javaMailProperties);
154 }
155 return this.session;
156 }
157
158
159
160
161 public void setProtocol(String protocol) {
162 this.protocol = protocol;
163 }
164
165
166
167
168 public String getProtocol() {
169 return this.protocol;
170 }
171
172
173
174
175
176 public void setHost(String host) {
177 this.host = host;
178 }
179
180
181
182
183 public String getHost() {
184 return this.host;
185 }
186
187
188
189
190
191
192 public void setPort(int port) {
193 this.port = port;
194 }
195
196
197
198
199 public int getPort() {
200 return this.port;
201 }
202
203
204
205
206
207
208
209
210
211
212
213
214 public void setUsername(String username) {
215 this.username = username;
216 }
217
218
219
220
221 public String getUsername() {
222 return this.username;
223 }
224
225
226
227
228
229
230
231
232
233
234
235
236 public void setPassword(String password) {
237 this.password = password;
238 }
239
240
241
242
243 public String getPassword() {
244 return this.password;
245 }
246
247
248
249
250
251
252 public void setDefaultEncoding(String defaultEncoding) {
253 this.defaultEncoding = defaultEncoding;
254 }
255
256
257
258
259
260 public String getDefaultEncoding() {
261 return this.defaultEncoding;
262 }
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277 public void setDefaultFileTypeMap(FileTypeMap defaultFileTypeMap) {
278 this.defaultFileTypeMap = defaultFileTypeMap;
279 }
280
281
282
283
284
285 public FileTypeMap getDefaultFileTypeMap() {
286 return this.defaultFileTypeMap;
287 }
288
289
290
291
292
293
294 @Override
295 public void send(SimpleMailMessage simpleMessage) throws MailException {
296 send(new SimpleMailMessage[] {simpleMessage});
297 }
298
299 @Override
300 public void send(SimpleMailMessage... simpleMessages) throws MailException {
301 List<MimeMessage> mimeMessages = new ArrayList<MimeMessage>(simpleMessages.length);
302 for (SimpleMailMessage simpleMessage : simpleMessages) {
303 MimeMailMessage message = new MimeMailMessage(createMimeMessage());
304 simpleMessage.copyTo(message);
305 mimeMessages.add(message.getMimeMessage());
306 }
307 doSend(mimeMessages.toArray(new MimeMessage[mimeMessages.size()]), simpleMessages);
308 }
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323 @Override
324 public MimeMessage createMimeMessage() {
325 return new SmartMimeMessage(getSession(), getDefaultEncoding(), getDefaultFileTypeMap());
326 }
327
328 @Override
329 public MimeMessage createMimeMessage(InputStream contentStream) throws MailException {
330 try {
331 return new MimeMessage(getSession(), contentStream);
332 }
333 catch (Exception ex) {
334 throw new MailParseException("Could not parse raw MIME content", ex);
335 }
336 }
337
338 @Override
339 public void send(MimeMessage mimeMessage) throws MailException {
340 send(new MimeMessage[] {mimeMessage});
341 }
342
343 @Override
344 public void send(MimeMessage... mimeMessages) throws MailException {
345 doSend(mimeMessages, null);
346 }
347
348 @Override
349 public void send(MimeMessagePreparator mimeMessagePreparator) throws MailException {
350 send(new MimeMessagePreparator[] {mimeMessagePreparator});
351 }
352
353 @Override
354 public void send(MimeMessagePreparator... mimeMessagePreparators) throws MailException {
355 try {
356 List<MimeMessage> mimeMessages = new ArrayList<MimeMessage>(mimeMessagePreparators.length);
357 for (MimeMessagePreparator preparator : mimeMessagePreparators) {
358 MimeMessage mimeMessage = createMimeMessage();
359 preparator.prepare(mimeMessage);
360 mimeMessages.add(mimeMessage);
361 }
362 send(mimeMessages.toArray(new MimeMessage[mimeMessages.size()]));
363 }
364 catch (MailException ex) {
365 throw ex;
366 }
367 catch (MessagingException ex) {
368 throw new MailParseException(ex);
369 }
370 catch (Exception ex) {
371 throw new MailPreparationException(ex);
372 }
373 }
374
375
376
377
378
379
380
381
382
383
384
385
386
387 protected void doSend(MimeMessage[] mimeMessages, Object[] originalMessages) throws MailException {
388 Map<Object, Exception> failedMessages = new LinkedHashMap<Object, Exception>();
389 Transport transport = null;
390
391 try {
392 for (int i = 0; i < mimeMessages.length; i++) {
393
394
395 if (transport == null || !transport.isConnected()) {
396 if (transport != null) {
397 try {
398 transport.close();
399 }
400 catch (Exception ex) {
401
402 }
403 transport = null;
404 }
405 try {
406 transport = connectTransport();
407 }
408 catch (AuthenticationFailedException ex) {
409 throw new MailAuthenticationException(ex);
410 }
411 catch (Exception ex) {
412
413 for (int j = i; j < mimeMessages.length; j++) {
414 Object original = (originalMessages != null ? originalMessages[j] : mimeMessages[j]);
415 failedMessages.put(original, ex);
416 }
417 throw new MailSendException("Mail server connection failed", ex, failedMessages);
418 }
419 }
420
421
422 MimeMessage mimeMessage = mimeMessages[i];
423 try {
424 if (mimeMessage.getSentDate() == null) {
425 mimeMessage.setSentDate(new Date());
426 }
427 String messageId = mimeMessage.getMessageID();
428 mimeMessage.saveChanges();
429 if (messageId != null) {
430
431 mimeMessage.setHeader(HEADER_MESSAGE_ID, messageId);
432 }
433 transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients());
434 }
435 catch (Exception ex) {
436 Object original = (originalMessages != null ? originalMessages[i] : mimeMessage);
437 failedMessages.put(original, ex);
438 }
439 }
440 }
441 finally {
442 try {
443 if (transport != null) {
444 transport.close();
445 }
446 }
447 catch (Exception ex) {
448 if (!failedMessages.isEmpty()) {
449 throw new MailSendException("Failed to close server connection after message failures", ex,
450 failedMessages);
451 }
452 else {
453 throw new MailSendException("Failed to close server connection after message sending", ex);
454 }
455 }
456 }
457
458 if (!failedMessages.isEmpty()) {
459 throw new MailSendException(failedMessages);
460 }
461 }
462
463
464
465
466
467
468
469
470
471
472
473
474
475 protected Transport connectTransport() throws MessagingException {
476 String username = getUsername();
477 String password = getPassword();
478 if ("".equals(username)) {
479 username = null;
480 if ("".equals(password)) {
481 password = null;
482 }
483 }
484
485 Transport transport = getTransport(getSession());
486 transport.connect(getHost(), getPort(), username, password);
487 return transport;
488 }
489
490
491
492
493
494
495
496
497
498 protected Transport getTransport(Session session) throws NoSuchProviderException {
499 String protocol = getProtocol();
500 if (protocol == null) {
501 protocol = session.getProperty("mail.transport.protocol");
502 if (protocol == null) {
503 protocol = DEFAULT_PROTOCOL;
504 }
505 }
506 return session.getTransport(protocol);
507 }
508
509 }