0
# Event Handling System
1
2
Jakarta Mail's event handling system provides comprehensive asynchronous notifications for mail operations including connection changes, folder operations, message modifications, and transport events.
3
4
## Event Foundation
5
6
All mail events extend the base MailEvent class which provides common event functionality.
7
8
```java { .api }
9
public abstract class MailEvent extends EventObject {
10
// Constructor
11
protected MailEvent(Object source);
12
13
// Source access (inherited from EventObject)
14
public Object getSource();
15
16
// String representation
17
public String toString();
18
}
19
```
20
21
## Connection Events
22
23
Connection events track the state of connections to mail stores and transports.
24
25
```java { .api }
26
public final class ConnectionEvent extends MailEvent {
27
// Event type constants
28
public static final int OPENED = 1;
29
public static final int DISCONNECTED = 2;
30
public static final int CLOSED = 3;
31
32
// Constructors
33
public ConnectionEvent(Object source, int type);
34
35
// Event type access
36
public int getType();
37
38
// Utility methods
39
public void dispatch(Object listener);
40
}
41
```
42
43
### Connection Listener Interface
44
45
```java { .api }
46
public interface ConnectionListener extends EventListener {
47
public void opened(ConnectionEvent e);
48
public void disconnected(ConnectionEvent e);
49
public void closed(ConnectionEvent e);
50
}
51
```
52
53
### Connection Adapter
54
55
```java { .api }
56
public abstract class ConnectionAdapter implements ConnectionListener {
57
public void opened(ConnectionEvent e) {}
58
public void disconnected(ConnectionEvent e) {}
59
public void closed(ConnectionEvent e) {}
60
}
61
```
62
63
### Connection Event Usage Example
64
65
```java
66
import jakarta.mail.event.*;
67
import jakarta.mail.*;
68
69
// Create connection listener
70
ConnectionListener connectionListener = new ConnectionListener() {
71
@Override
72
public void opened(ConnectionEvent e) {
73
System.out.println("Connection opened to: " + e.getSource());
74
}
75
76
@Override
77
public void disconnected(ConnectionEvent e) {
78
System.out.println("Connection lost to: " + e.getSource());
79
// Could implement reconnection logic here
80
}
81
82
@Override
83
public void closed(ConnectionEvent e) {
84
System.out.println("Connection closed to: " + e.getSource());
85
}
86
};
87
88
// Add listener to store
89
Store store = session.getStore("imaps");
90
store.addConnectionListener(connectionListener);
91
92
// Add listener to transport
93
Transport transport = session.getTransport("smtp");
94
transport.addConnectionListener(connectionListener);
95
96
// Connections now generate events
97
store.connect("imap.example.com", "user", "password"); // Fires opened event
98
transport.connect(); // Fires opened event
99
store.close(); // Fires closed event
100
101
// Using adapter for selective handling
102
store.addConnectionListener(new ConnectionAdapter() {
103
@Override
104
public void disconnected(ConnectionEvent e) {
105
// Only handle disconnection events
106
System.err.println("Store connection lost - attempting reconnect");
107
reconnectStore((Store) e.getSource());
108
}
109
});
110
```
111
112
## Folder Events
113
114
Folder events track structural changes to folders including creation, deletion, and renaming.
115
116
```java { .api }
117
public final class FolderEvent extends MailEvent {
118
// Event type constants
119
public static final int CREATED = 1;
120
public static final int DELETED = 2;
121
public static final int RENAMED = 3;
122
123
// Constructors
124
public FolderEvent(Object source, Folder folder, int type);
125
public FolderEvent(Object source, Folder folder, Folder newFolder, int type);
126
127
// Event access
128
public int getType();
129
public Folder getFolder();
130
public Folder getNewFolder(); // For rename events
131
132
// Utility methods
133
public void dispatch(Object listener);
134
}
135
```
136
137
### Folder Listener Interface
138
139
```java { .api }
140
public interface FolderListener extends EventListener {
141
public void folderCreated(FolderEvent e);
142
public void folderDeleted(FolderEvent e);
143
public void folderRenamed(FolderEvent e);
144
}
145
```
146
147
### Folder Adapter
148
149
```java { .api }
150
public abstract class FolderAdapter implements FolderListener {
151
public void folderCreated(FolderEvent e) {}
152
public void folderDeleted(FolderEvent e) {}
153
public void folderRenamed(FolderEvent e) {}
154
}
155
```
156
157
### Folder Event Usage Example
158
159
```java
160
import jakarta.mail.event.*;
161
import jakarta.mail.*;
162
163
// Create folder listener
164
FolderListener folderListener = new FolderListener() {
165
@Override
166
public void folderCreated(FolderEvent e) {
167
System.out.println("Folder created: " + e.getFolder().getFullName());
168
}
169
170
@Override
171
public void folderDeleted(FolderEvent e) {
172
System.out.println("Folder deleted: " + e.getFolder().getFullName());
173
}
174
175
@Override
176
public void folderRenamed(FolderEvent e) {
177
System.out.println("Folder renamed from " + e.getFolder().getFullName() +
178
" to " + e.getNewFolder().getFullName());
179
}
180
};
181
182
// Add listener to store
183
Store store = session.getStore("imaps");
184
store.addFolderListener(folderListener);
185
186
// Folder operations now generate events
187
Folder newFolder = store.getFolder("NewFolder");
188
newFolder.create(Folder.HOLDS_MESSAGES); // Fires created event
189
190
Folder renamedFolder = store.getFolder("RenamedFolder");
191
newFolder.renameTo(renamedFolder); // Fires renamed event
192
193
// Using adapter for specific events only
194
store.addFolderListener(new FolderAdapter() {
195
@Override
196
public void folderDeleted(FolderEvent e) {
197
// Log folder deletions for audit purposes
198
auditLog("Folder deleted: " + e.getFolder().getFullName());
199
}
200
});
201
```
202
203
## Message Count Events
204
205
Message count events track additions and removals of messages from folders.
206
207
```java { .api }
208
public final class MessageCountEvent extends MailEvent {
209
// Event type constants
210
public static final int ADDED = 1;
211
public static final int REMOVED = 2;
212
213
// Constructors
214
public MessageCountEvent(Folder source, int type, boolean removed, Message[] msgs);
215
216
// Event access
217
public int getType();
218
public boolean isRemoved();
219
public Message[] getMessages();
220
221
// Utility methods
222
public void dispatch(Object listener);
223
}
224
```
225
226
### Message Count Listener Interface
227
228
```java { .api }
229
public interface MessageCountListener extends EventListener {
230
public void messagesAdded(MessageCountEvent e);
231
public void messagesRemoved(MessageCountEvent e);
232
}
233
```
234
235
### Message Count Adapter
236
237
```java { .api }
238
public abstract class MessageCountAdapter implements MessageCountListener {
239
public void messagesAdded(MessageCountEvent e) {}
240
public void messagesRemoved(MessageCountEvent e) {}
241
}
242
```
243
244
### Message Count Event Usage Example
245
246
```java
247
import jakarta.mail.event.*;
248
import jakarta.mail.*;
249
250
// Create message count listener
251
MessageCountListener messageCountListener = new MessageCountListener() {
252
@Override
253
public void messagesAdded(MessageCountEvent e) {
254
Message[] newMessages = e.getMessages();
255
System.out.println(newMessages.length + " new messages arrived");
256
257
// Process new messages
258
for (Message message : newMessages) {
259
try {
260
System.out.println("New message: " + message.getSubject());
261
// Could trigger notifications, auto-processing, etc.
262
} catch (MessagingException ex) {
263
System.err.println("Error processing new message: " + ex.getMessage());
264
}
265
}
266
}
267
268
@Override
269
public void messagesRemoved(MessageCountEvent e) {
270
Message[] removedMessages = e.getMessages();
271
System.out.println(removedMessages.length + " messages removed");
272
}
273
};
274
275
// Add listener to folder
276
Folder inbox = store.getFolder("INBOX");
277
inbox.addMessageCountListener(messageCountListener);
278
279
// Open folder to enable event generation
280
inbox.open(Folder.READ_WRITE);
281
282
// Message operations now generate events
283
// (New messages arriving via IMAP IDLE or manual refresh will fire events)
284
285
// Using adapter for new message notifications only
286
inbox.addMessageCountListener(new MessageCountAdapter() {
287
@Override
288
public void messagesAdded(MessageCountEvent e) {
289
// Send desktop notification for new messages
290
showNotification(e.getMessages().length + " new messages");
291
292
// Update UI badge count
293
updateUnreadCount();
294
}
295
});
296
```
297
298
## Message Changed Events
299
300
Message changed events track modifications to message flags and headers.
301
302
```java { .api }
303
public final class MessageChangedEvent extends MailEvent {
304
// Event type constants
305
public static final int FLAGS_CHANGED = 1;
306
public static final int ENVELOPE_CHANGED = 2;
307
308
// Constructors
309
public MessageChangedEvent(Object source, int type, Message msg);
310
311
// Event access
312
public int getType();
313
public Message getMessage();
314
315
// Utility methods
316
public void dispatch(Object listener);
317
}
318
```
319
320
### Message Changed Listener Interface
321
322
```java { .api }
323
public interface MessageChangedListener extends EventListener {
324
public void messageChanged(MessageChangedEvent e);
325
}
326
```
327
328
### Message Changed Event Usage Example
329
330
```java
331
import jakarta.mail.event.*;
332
import jakarta.mail.*;
333
334
// Create message changed listener
335
MessageChangedListener messageChangedListener = new MessageChangedListener() {
336
@Override
337
public void messageChanged(MessageChangedEvent e) {
338
Message changedMessage = e.getMessage();
339
340
switch (e.getType()) {
341
case MessageChangedEvent.FLAGS_CHANGED:
342
try {
343
System.out.println("Flags changed for message: " + changedMessage.getSubject());
344
Flags flags = changedMessage.getFlags();
345
346
if (flags.contains(Flags.Flag.SEEN)) {
347
System.out.println("Message marked as read");
348
updateReadCount();
349
}
350
351
if (flags.contains(Flags.Flag.FLAGGED)) {
352
System.out.println("Message flagged");
353
addToImportantList(changedMessage);
354
}
355
356
if (flags.contains(Flags.Flag.DELETED)) {
357
System.out.println("Message marked for deletion");
358
}
359
360
} catch (MessagingException ex) {
361
System.err.println("Error processing flag change: " + ex.getMessage());
362
}
363
break;
364
365
case MessageChangedEvent.ENVELOPE_CHANGED:
366
System.out.println("Envelope changed for message");
367
// Headers like subject, from, to have changed
368
refreshMessageDisplay(changedMessage);
369
break;
370
}
371
}
372
};
373
374
// Add listener to folder
375
Folder folder = store.getFolder("INBOX");
376
folder.addMessageChangedListener(messageChangedListener);
377
378
// Message flag changes now generate events
379
Message message = folder.getMessage(1);
380
message.setFlag(Flags.Flag.SEEN, true); // Fires FLAGS_CHANGED event
381
message.setFlag(Flags.Flag.FLAGGED, true); // Fires FLAGS_CHANGED event
382
```
383
384
## Store Events
385
386
Store events provide general notifications and alerts from mail stores.
387
388
```java { .api }
389
public final class StoreEvent extends MailEvent {
390
// Event type constants
391
public static final int ALERT = 1;
392
public static final int NOTICE = 2;
393
394
// Constructors
395
public StoreEvent(Store source, int type, String message);
396
397
// Event access
398
public int getType();
399
public String getMessage();
400
401
// Utility methods
402
public void dispatch(Object listener);
403
}
404
```
405
406
### Store Listener Interface
407
408
```java { .api }
409
public interface StoreListener extends EventListener {
410
public void notification(StoreEvent e);
411
}
412
```
413
414
### Store Event Usage Example
415
416
```java
417
import jakarta.mail.event.*;
418
import jakarta.mail.*;
419
420
// Create store listener
421
StoreListener storeListener = new StoreListener() {
422
@Override
423
public void notification(StoreEvent e) {
424
switch (e.getType()) {
425
case StoreEvent.ALERT:
426
System.err.println("Store Alert: " + e.getMessage());
427
// Handle critical store alerts
428
handleStoreAlert(e.getMessage());
429
break;
430
431
case StoreEvent.NOTICE:
432
System.out.println("Store Notice: " + e.getMessage());
433
// Handle informational notices
434
logStoreNotice(e.getMessage());
435
break;
436
}
437
}
438
};
439
440
// Add listener to store
441
Store store = session.getStore("imaps");
442
store.addStoreListener(storeListener);
443
444
// Store operations may generate events
445
// Examples: quota warnings, maintenance notices, server messages
446
```
447
448
## Transport Events
449
450
Transport events track message delivery status and transmission results.
451
452
```java { .api }
453
public final class TransportEvent extends MailEvent {
454
// Event type constants
455
public static final int MESSAGE_DELIVERED = 1;
456
public static final int MESSAGE_NOT_DELIVERED = 2;
457
public static final int MESSAGE_PARTIALLY_DELIVERED = 3;
458
459
// Constructors
460
public TransportEvent(Transport source, int type, Address[] validSent,
461
Address[] validUnsent, Address[] invalid, Message msg);
462
463
// Event access
464
public int getType();
465
public Address[] getValidSentAddresses();
466
public Address[] getValidUnsentAddresses();
467
public Address[] getInvalidAddresses();
468
public Message getMessage();
469
470
// Utility methods
471
public void dispatch(Object listener);
472
}
473
```
474
475
### Transport Listener Interface
476
477
```java { .api }
478
public interface TransportListener extends EventListener {
479
public void messageDelivered(TransportEvent e);
480
public void messageNotDelivered(TransportEvent e);
481
public void messagePartiallyDelivered(TransportEvent e);
482
}
483
```
484
485
### Transport Adapter
486
487
```java { .api }
488
public abstract class TransportAdapter implements TransportListener {
489
public void messageDelivered(TransportEvent e) {}
490
public void messageNotDelivered(TransportEvent e) {}
491
public void messagePartiallyDelivered(TransportEvent e) {}
492
}
493
```
494
495
### Transport Event Usage Example
496
497
```java
498
import jakarta.mail.event.*;
499
import jakarta.mail.*;
500
import jakarta.mail.internet.*;
501
502
// Create transport listener
503
TransportListener transportListener = new TransportListener() {
504
@Override
505
public void messageDelivered(TransportEvent e) {
506
System.out.println("Message delivered successfully");
507
Address[] delivered = e.getValidSentAddresses();
508
for (Address addr : delivered) {
509
System.out.println("Delivered to: " + addr.toString());
510
}
511
512
// Update message status, log delivery, etc.
513
logDelivery(e.getMessage(), delivered);
514
}
515
516
@Override
517
public void messageNotDelivered(TransportEvent e) {
518
System.err.println("Message delivery failed");
519
Address[] failed = e.getValidUnsentAddresses();
520
Address[] invalid = e.getInvalidAddresses();
521
522
for (Address addr : failed) {
523
System.err.println("Failed to deliver to: " + addr.toString());
524
}
525
526
for (Address addr : invalid) {
527
System.err.println("Invalid address: " + addr.toString());
528
}
529
530
// Handle delivery failure
531
handleDeliveryFailure(e.getMessage(), failed, invalid);
532
}
533
534
@Override
535
public void messagePartiallyDelivered(TransportEvent e) {
536
System.out.println("Message partially delivered");
537
538
Address[] delivered = e.getValidSentAddresses();
539
Address[] failed = e.getValidUnsentAddresses();
540
Address[] invalid = e.getInvalidAddresses();
541
542
System.out.println("Delivered to " + delivered.length + " recipients");
543
System.out.println("Failed to deliver to " + failed.length + " recipients");
544
System.out.println("Invalid addresses: " + invalid.length);
545
546
// Handle partial delivery
547
handlePartialDelivery(e.getMessage(), delivered, failed, invalid);
548
}
549
};
550
551
// Add listener to transport
552
Transport transport = session.getTransport("smtp");
553
transport.addTransportListener(transportListener);
554
555
// Send message - events will be generated
556
MimeMessage message = new MimeMessage(session);
557
message.setFrom(new InternetAddress("sender@example.com"));
558
message.setRecipients(Message.RecipientType.TO,
559
InternetAddress.parse("valid@example.com,invalid-address,another@example.com"));
560
message.setSubject("Test Message");
561
message.setText("Test content");
562
563
transport.connect();
564
transport.sendMessage(message, message.getAllRecipients());
565
transport.close();
566
567
// Using adapter for delivery confirmation only
568
transport.addTransportListener(new TransportAdapter() {
569
@Override
570
public void messageDelivered(TransportEvent e) {
571
// Send confirmation to sender
572
sendDeliveryConfirmation(e.getMessage());
573
}
574
});
575
```
576
577
## Event Management Patterns
578
579
### Centralized Event Handler
580
581
```java
582
public class MailEventManager implements ConnectionListener, FolderListener,
583
MessageCountListener, MessageChangedListener,
584
StoreListener, TransportListener {
585
586
private final List<MailEventObserver> observers = new ArrayList<>();
587
588
public void addObserver(MailEventObserver observer) {
589
observers.add(observer);
590
}
591
592
// Connection events
593
@Override
594
public void opened(ConnectionEvent e) {
595
notifyObservers("Connection opened: " + e.getSource());
596
}
597
598
@Override
599
public void disconnected(ConnectionEvent e) {
600
notifyObservers("Connection lost: " + e.getSource());
601
// Attempt reconnection
602
scheduleReconnection((Service) e.getSource());
603
}
604
605
@Override
606
public void closed(ConnectionEvent e) {
607
notifyObservers("Connection closed: " + e.getSource());
608
}
609
610
// Message count events
611
@Override
612
public void messagesAdded(MessageCountEvent e) {
613
notifyObservers(e.getMessages().length + " new messages");
614
updateNotificationBadge();
615
}
616
617
@Override
618
public void messagesRemoved(MessageCountEvent e) {
619
notifyObservers(e.getMessages().length + " messages removed");
620
updateNotificationBadge();
621
}
622
623
// Message changed events
624
@Override
625
public void messageChanged(MessageChangedEvent e) {
626
if (e.getType() == MessageChangedEvent.FLAGS_CHANGED) {
627
updateMessageFlags(e.getMessage());
628
}
629
}
630
631
// Transport events
632
@Override
633
public void messageDelivered(TransportEvent e) {
634
notifyObservers("Message delivered successfully");
635
}
636
637
@Override
638
public void messageNotDelivered(TransportEvent e) {
639
notifyObservers("Message delivery failed");
640
handleDeliveryFailure(e);
641
}
642
643
@Override
644
public void messagePartiallyDelivered(TransportEvent e) {
645
notifyObservers("Message partially delivered");
646
handlePartialDelivery(e);
647
}
648
649
// Other event implementations...
650
651
private void notifyObservers(String message) {
652
for (MailEventObserver observer : observers) {
653
observer.onEvent(message);
654
}
655
}
656
}
657
658
// Register the centralized handler
659
MailEventManager eventManager = new MailEventManager();
660
store.addConnectionListener(eventManager);
661
folder.addMessageCountListener(eventManager);
662
transport.addTransportListener(eventManager);
663
```
664
665
### Asynchronous Event Processing
666
667
```java
668
public class AsyncEventProcessor {
669
private final ExecutorService eventExecutor = Executors.newCachedThreadPool();
670
671
public void processMessageCountEvent(MessageCountEvent e) {
672
eventExecutor.submit(() -> {
673
try {
674
// Process new messages asynchronously
675
for (Message message : e.getMessages()) {
676
processNewMessage(message);
677
}
678
} catch (Exception ex) {
679
System.err.println("Error processing messages: " + ex.getMessage());
680
}
681
});
682
}
683
684
public void processTransportEvent(TransportEvent e) {
685
eventExecutor.submit(() -> {
686
// Update delivery status in database
687
updateDeliveryStatus(e);
688
689
// Send notifications
690
sendDeliveryNotifications(e);
691
});
692
}
693
694
public void shutdown() {
695
eventExecutor.shutdown();
696
}
697
}
698
```
699
700
### Event Filtering and Routing
701
702
```java
703
public class EventRouter {
704
private final Map<Class<?>, List<Object>> listenerMap = new HashMap<>();
705
706
public void addListener(Class<?> eventType, Object listener) {
707
listenerMap.computeIfAbsent(eventType, k -> new ArrayList<>()).add(listener);
708
}
709
710
public void routeEvent(Object event) {
711
Class<?> eventType = event.getClass();
712
List<Object> listeners = listenerMap.get(eventType);
713
714
if (listeners != null) {
715
for (Object listener : listeners) {
716
try {
717
if (event instanceof MessageCountEvent && listener instanceof MessageCountListener) {
718
MessageCountEvent mce = (MessageCountEvent) event;
719
MessageCountListener mcl = (MessageCountListener) listener;
720
721
if (mce.getType() == MessageCountEvent.ADDED) {
722
mcl.messagesAdded(mce);
723
} else {
724
mcl.messagesRemoved(mce);
725
}
726
}
727
// Handle other event types...
728
} catch (Exception e) {
729
System.err.println("Error in event listener: " + e.getMessage());
730
}
731
}
732
}
733
}
734
}
735
```