or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-mail-operations.mdevent-handling-system.mdindex.mdinternet-mail-mime.mdmessage-search-filtering.mdstore-folder-management.mdutility-classes-streams.md

event-handling-system.mddocs/

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

```