or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-messaging.mdevent-handling.mdfolder-operations.mdindex.mdinternet-messaging.mdsearch-capabilities.md

event-handling.mddocs/

0

# Event Handling

1

2

This document covers the comprehensive event-driven programming capabilities of the Jakarta Mail API, including connection events, message changes, folder operations, and transport notifications.

3

4

## Event System Overview

5

6

The Jakarta Mail API provides an event-driven architecture for monitoring mail operations. Events are fired for connections, folder changes, message modifications, and transport operations.

7

8

### Base Event Class

9

10

```java { .api }

11

abstract class MailEvent extends EventObject {

12

public MailEvent(Object source);

13

14

public abstract void dispatch(Object listener);

15

}

16

```

17

18

All mail events extend this base class and implement the `dispatch` method to deliver themselves to appropriate listener methods.

19

20

## Connection Events

21

22

Connection events are fired when mail service connections are opened, closed, or disconnected unexpectedly.

23

24

### ConnectionEvent Class

25

26

```java { .api }

27

class ConnectionEvent extends MailEvent {

28

public static final int OPENED = 1;

29

public static final int DISCONNECTED = 2;

30

public static final int CLOSED = 3;

31

32

public ConnectionEvent(Object source, int type);

33

34

public int getType();

35

public void dispatch(Object listener);

36

}

37

```

38

39

### ConnectionListener Interface

40

41

```java { .api }

42

interface ConnectionListener extends EventListener {

43

public void opened(ConnectionEvent e);

44

public void disconnected(ConnectionEvent e);

45

public void closed(ConnectionEvent e);

46

}

47

```

48

49

### ConnectionAdapter Class

50

51

```java { .api }

52

abstract class ConnectionAdapter implements ConnectionListener {

53

public void opened(ConnectionEvent e) {}

54

public void disconnected(ConnectionEvent e) {}

55

public void closed(ConnectionEvent e) {}

56

}

57

```

58

59

### Connection Event Usage

60

61

```java

62

public class ConnectionMonitor extends ConnectionAdapter {

63

64

@Override

65

public void opened(ConnectionEvent e) {

66

System.out.println("Connection opened: " + e.getSource());

67

}

68

69

@Override

70

public void disconnected(ConnectionEvent e) {

71

System.err.println("Connection lost: " + e.getSource());

72

handleDisconnection();

73

}

74

75

@Override

76

public void closed(ConnectionEvent e) {

77

System.out.println("Connection closed: " + e.getSource());

78

}

79

80

private void handleDisconnection() {

81

// Implement reconnection logic

82

System.out.println("Attempting to reconnect...");

83

}

84

}

85

86

// Register connection listener

87

Store store = session.getStore("imap");

88

store.addConnectionListener(new ConnectionMonitor());

89

store.connect();

90

```

91

92

## Folder Events

93

94

Folder events are fired when folders are created, deleted, or renamed in the message store.

95

96

### FolderEvent Class

97

98

```java { .api }

99

class FolderEvent extends MailEvent {

100

public static final int CREATED = 1;

101

public static final int DELETED = 2;

102

public static final int RENAMED = 3;

103

104

protected Folder folder;

105

protected Folder newFolder;

106

107

public FolderEvent(Object source, Folder folder, int type);

108

public FolderEvent(Object source, Folder oldFolder, Folder newFolder, int type);

109

110

public int getType();

111

public Folder getFolder();

112

public Folder getNewFolder();

113

public void dispatch(Object listener);

114

}

115

```

116

117

### FolderListener Interface

118

119

```java { .api }

120

interface FolderListener extends EventListener {

121

public void folderCreated(FolderEvent e);

122

public void folderDeleted(FolderEvent e);

123

public void folderRenamed(FolderEvent e);

124

}

125

```

126

127

### FolderAdapter Class

128

129

```java { .api }

130

abstract class FolderAdapter implements FolderListener {

131

public void folderCreated(FolderEvent e) {}

132

public void folderDeleted(FolderEvent e) {}

133

public void folderRenamed(FolderEvent e) {}

134

}

135

```

136

137

### Folder Event Usage

138

139

```java

140

public class FolderMonitor extends FolderAdapter {

141

142

@Override

143

public void folderCreated(FolderEvent e) {

144

Folder newFolder = e.getFolder();

145

System.out.println("New folder created: " + newFolder.getFullName());

146

147

// Update folder cache or UI

148

updateFolderList();

149

}

150

151

@Override

152

public void folderDeleted(FolderEvent e) {

153

Folder deletedFolder = e.getFolder();

154

System.out.println("Folder deleted: " + deletedFolder.getFullName());

155

156

// Clean up references

157

removeFolderFromCache(deletedFolder);

158

}

159

160

@Override

161

public void folderRenamed(FolderEvent e) {

162

Folder oldFolder = e.getFolder();

163

Folder newFolder = e.getNewFolder();

164

System.out.println("Folder renamed: " + oldFolder.getFullName() +

165

" -> " + newFolder.getFullName());

166

167

// Update references

168

updateFolderReferences(oldFolder, newFolder);

169

}

170

171

private void updateFolderList() { /* Implementation */ }

172

private void removeFolderFromCache(Folder folder) { /* Implementation */ }

173

private void updateFolderReferences(Folder old, Folder newFolder) { /* Implementation */ }

174

}

175

176

// Register folder listener

177

Store store = session.getStore("imap");

178

store.addFolderListener(new FolderMonitor());

179

```

180

181

## Message Count Events

182

183

Message count events are fired when messages are added to or removed from folders.

184

185

### MessageCountEvent Class

186

187

```java { .api }

188

class MessageCountEvent extends MailEvent {

189

public static final int ADDED = 1;

190

public static final int REMOVED = 2;

191

192

protected int type;

193

protected boolean removed;

194

protected Message[] msgs;

195

196

public MessageCountEvent(Folder folder, int type, boolean removed, Message[] msgs);

197

198

public int getType();

199

public boolean isRemoved();

200

public Message[] getMessages();

201

public void dispatch(Object listener);

202

}

203

```

204

205

### MessageCountListener Interface

206

207

```java { .api }

208

interface MessageCountListener extends EventListener {

209

public void messagesAdded(MessageCountEvent e);

210

public void messagesRemoved(MessageCountEvent e);

211

}

212

```

213

214

### MessageCountAdapter Class

215

216

```java { .api }

217

abstract class MessageCountAdapter implements MessageCountListener {

218

public void messagesAdded(MessageCountEvent e) {}

219

public void messagesRemoved(MessageCountEvent e) {}

220

}

221

```

222

223

### Message Count Event Usage

224

225

```java

226

public class MessageMonitor extends MessageCountAdapter {

227

private int totalMessages = 0;

228

229

@Override

230

public void messagesAdded(MessageCountEvent e) {

231

Message[] newMessages = e.getMessages();

232

totalMessages += newMessages.length;

233

234

System.out.println(newMessages.length + " new messages arrived");

235

System.out.println("Total messages: " + totalMessages);

236

237

// Process new messages

238

for (Message msg : newMessages) {

239

try {

240

processNewMessage(msg);

241

} catch (MessagingException ex) {

242

System.err.println("Error processing message: " + ex.getMessage());

243

}

244

}

245

}

246

247

@Override

248

public void messagesRemoved(MessageCountEvent e) {

249

Message[] removedMessages = e.getMessages();

250

totalMessages -= removedMessages.length;

251

252

System.out.println(removedMessages.length + " messages removed");

253

System.out.println("Total messages: " + totalMessages);

254

255

// Clean up references

256

for (Message msg : removedMessages) {

257

cleanupMessage(msg);

258

}

259

}

260

261

private void processNewMessage(Message msg) throws MessagingException {

262

// Handle new message arrival

263

System.out.println("New message: " + msg.getSubject());

264

265

// Check for important messages

266

if (isImportant(msg)) {

267

notifyUser(msg);

268

}

269

}

270

271

private boolean isImportant(Message msg) throws MessagingException {

272

return msg.isSet(Flags.Flag.FLAGGED) ||

273

(msg.getSubject() != null && msg.getSubject().contains("URGENT"));

274

}

275

276

private void notifyUser(Message msg) {

277

// Implementation for user notification

278

System.out.println("IMPORTANT MESSAGE RECEIVED!");

279

}

280

281

private void cleanupMessage(Message msg) {

282

// Clean up message references

283

System.out.println("Cleaning up message references");

284

}

285

}

286

287

// Register message count listener

288

Folder folder = store.getFolder("INBOX");

289

folder.addMessageCountListener(new MessageMonitor());

290

folder.open(Folder.READ_WRITE);

291

```

292

293

## Message Changed Events

294

295

Message changed events are fired when message properties (flags, headers, content) are modified.

296

297

### MessageChangedEvent Class

298

299

```java { .api }

300

class MessageChangedEvent extends MailEvent {

301

protected int type;

302

protected Message msg;

303

304

public MessageChangedEvent(Object source, int type, Message message);

305

306

public int getType();

307

public Message getMessage();

308

public void dispatch(Object listener);

309

}

310

```

311

312

### MessageChangedListener Interface

313

314

```java { .api }

315

interface MessageChangedListener extends EventListener {

316

public void messageChanged(MessageChangedEvent e);

317

}

318

```

319

320

### Message Changed Event Usage

321

322

```java

323

public class MessageChangeMonitor implements MessageChangedListener {

324

325

@Override

326

public void messageChanged(MessageChangedEvent e) {

327

Message msg = e.getMessage();

328

329

try {

330

System.out.println("Message changed: " + msg.getSubject());

331

332

// Check what changed

333

if (msg.isSet(Flags.Flag.SEEN)) {

334

System.out.println("Message marked as read");

335

}

336

337

if (msg.isSet(Flags.Flag.FLAGGED)) {

338

System.out.println("Message flagged as important");

339

}

340

341

if (msg.isSet(Flags.Flag.DELETED)) {

342

System.out.println("Message marked for deletion");

343

}

344

345

// Update UI or cache

346

updateMessageDisplay(msg);

347

348

} catch (MessagingException ex) {

349

System.err.println("Error handling message change: " + ex.getMessage());

350

}

351

}

352

353

private void updateMessageDisplay(Message msg) {

354

// Update UI representation of the message

355

System.out.println("Updating message display");

356

}

357

}

358

359

// Register message changed listener

360

folder.addMessageChangedListener(new MessageChangeMonitor());

361

```

362

363

## Store Events

364

365

Store events provide general notifications about store-level operations.

366

367

### StoreEvent Class

368

369

```java { .api }

370

class StoreEvent extends MailEvent {

371

protected int type;

372

protected String message;

373

374

public StoreEvent(Store store, int type, String message);

375

376

public int getType();

377

public String getMessage();

378

public void dispatch(Object listener);

379

}

380

```

381

382

### StoreListener Interface

383

384

```java { .api }

385

interface StoreListener extends EventListener {

386

public void notification(StoreEvent e);

387

}

388

```

389

390

### Store Event Usage

391

392

```java

393

public class StoreMonitor implements StoreListener {

394

395

@Override

396

public void notification(StoreEvent e) {

397

System.out.println("Store notification: " + e.getMessage());

398

399

// Handle different types of store events

400

int eventType = e.getType();

401

switch (eventType) {

402

case StoreEvent.ALERT:

403

handleAlert(e.getMessage());

404

break;

405

case StoreEvent.NOTICE:

406

handleNotice(e.getMessage());

407

break;

408

default:

409

handleGenericEvent(e.getMessage());

410

break;

411

}

412

}

413

414

private void handleAlert(String message) {

415

System.err.println("STORE ALERT: " + message);

416

// Handle critical store alerts

417

}

418

419

private void handleNotice(String message) {

420

System.out.println("Store notice: " + message);

421

// Handle informational notices

422

}

423

424

private void handleGenericEvent(String message) {

425

System.out.println("Store event: " + message);

426

}

427

}

428

429

// Register store listener

430

store.addStoreListener(new StoreMonitor());

431

```

432

433

## Transport Events

434

435

Transport events are fired during message sending operations to report delivery status.

436

437

### TransportEvent Class

438

439

```java { .api }

440

class TransportEvent extends MailEvent {

441

public static final int MESSAGE_DELIVERED = 1;

442

public static final int MESSAGE_NOT_DELIVERED = 2;

443

public static final int MESSAGE_PARTIALLY_DELIVERED = 3;

444

445

protected int type;

446

protected Address[] validSent;

447

protected Address[] validUnsent;

448

protected Address[] invalid;

449

protected Message msg;

450

451

public TransportEvent(Transport transport, int type, Address[] validSent,

452

Address[] validUnsent, Address[] invalid, Message msg);

453

454

public int getType();

455

public Address[] getValidSentAddresses();

456

public Address[] getValidUnsentAddresses();

457

public Address[] getInvalidAddresses();

458

public Message getMessage();

459

public void dispatch(Object listener);

460

}

461

```

462

463

### TransportListener Interface

464

465

```java { .api }

466

interface TransportListener extends EventListener {

467

public void messageDelivered(TransportEvent e);

468

public void messageNotDelivered(TransportEvent e);

469

public void messagePartiallyDelivered(TransportEvent e);

470

}

471

```

472

473

### TransportAdapter Class

474

475

```java { .api }

476

abstract class TransportAdapter implements TransportListener {

477

public void messageDelivered(TransportEvent e) {}

478

public void messageNotDelivered(TransportEvent e) {}

479

public void messagePartiallyDelivered(TransportEvent e) {}

480

}

481

```

482

483

### Transport Event Usage

484

485

```java

486

public class DeliveryMonitor extends TransportAdapter {

487

488

@Override

489

public void messageDelivered(TransportEvent e) {

490

Message msg = e.getMessage();

491

Address[] delivered = e.getValidSentAddresses();

492

493

try {

494

System.out.println("Message delivered successfully: " + msg.getSubject());

495

System.out.println("Delivered to " + delivered.length + " recipients:");

496

497

for (Address addr : delivered) {

498

System.out.println(" - " + addr.toString());

499

}

500

501

// Log successful delivery

502

logDelivery(msg, delivered, true);

503

504

} catch (MessagingException ex) {

505

System.err.println("Error processing delivery confirmation: " + ex.getMessage());

506

}

507

}

508

509

@Override

510

public void messageNotDelivered(TransportEvent e) {

511

Message msg = e.getMessage();

512

Address[] failed = e.getValidUnsentAddresses();

513

Address[] invalid = e.getInvalidAddresses();

514

515

try {

516

System.err.println("Message delivery failed: " + msg.getSubject());

517

518

if (failed != null && failed.length > 0) {

519

System.err.println("Failed addresses:");

520

for (Address addr : failed) {

521

System.err.println(" - " + addr.toString());

522

}

523

}

524

525

if (invalid != null && invalid.length > 0) {

526

System.err.println("Invalid addresses:");

527

for (Address addr : invalid) {

528

System.err.println(" - " + addr.toString());

529

}

530

}

531

532

// Log failed delivery and schedule retry

533

logDelivery(msg, failed, false);

534

scheduleRetry(msg, failed);

535

536

} catch (MessagingException ex) {

537

System.err.println("Error processing delivery failure: " + ex.getMessage());

538

}

539

}

540

541

@Override

542

public void messagePartiallyDelivered(TransportEvent e) {

543

Message msg = e.getMessage();

544

Address[] delivered = e.getValidSentAddresses();

545

Address[] failed = e.getValidUnsentAddresses();

546

547

try {

548

System.out.println("Message partially delivered: " + msg.getSubject());

549

550

if (delivered != null && delivered.length > 0) {

551

System.out.println("Successfully delivered to:");

552

for (Address addr : delivered) {

553

System.out.println(" - " + addr.toString());

554

}

555

}

556

557

if (failed != null && failed.length > 0) {

558

System.err.println("Failed to deliver to:");

559

for (Address addr : failed) {

560

System.err.println(" - " + addr.toString());

561

}

562

// Retry failed addresses

563

scheduleRetry(msg, failed);

564

}

565

566

} catch (MessagingException ex) {

567

System.err.println("Error processing partial delivery: " + ex.getMessage());

568

}

569

}

570

571

private void logDelivery(Message msg, Address[] addresses, boolean success) {

572

// Log delivery status to database or file

573

String status = success ? "DELIVERED" : "FAILED";

574

System.out.println("Logging delivery: " + status);

575

}

576

577

private void scheduleRetry(Message msg, Address[] failedAddresses) {

578

// Schedule retry for failed addresses

579

System.out.println("Scheduling retry for " + failedAddresses.length + " addresses");

580

}

581

}

582

583

// Register transport listener

584

Transport transport = session.getTransport("smtp");

585

transport.addTransportListener(new DeliveryMonitor());

586

```

587

588

## Complete Event Monitoring Example

589

590

```java

591

public class ComprehensiveMailMonitor {

592

593

public void setupEventMonitoring(Session session) throws MessagingException {

594

// Setup store monitoring

595

Store store = session.getStore("imap");

596

597

// Add connection monitoring

598

store.addConnectionListener(new ConnectionMonitor());

599

600

// Add folder monitoring

601

store.addFolderListener(new FolderMonitor());

602

603

// Add store-level monitoring

604

store.addStoreListener(new StoreMonitor());

605

606

store.connect();

607

608

// Setup folder-specific monitoring

609

Folder inbox = store.getFolder("INBOX");

610

611

// Add message count monitoring

612

inbox.addMessageCountListener(new MessageMonitor());

613

614

// Add message change monitoring

615

inbox.addMessageChangedListener(new MessageChangeMonitor());

616

617

inbox.open(Folder.READ_WRITE);

618

619

// Setup transport monitoring

620

Transport transport = session.getTransport("smtp");

621

transport.addTransportListener(new DeliveryMonitor());

622

623

// Keep connection alive and monitor events

624

monitorEvents(store, inbox, transport);

625

}

626

627

private void monitorEvents(Store store, Folder folder, Transport transport) {

628

// Keep the application running to receive events

629

Runtime.getRuntime().addShutdownHook(new Thread(() -> {

630

try {

631

System.out.println("Shutting down mail monitoring...");

632

folder.close();

633

store.close();

634

transport.close();

635

} catch (MessagingException e) {

636

System.err.println("Error during shutdown: " + e.getMessage());

637

}

638

}));

639

640

// Keep alive with periodic operations

641

Timer keepAliveTimer = new Timer(true);

642

keepAliveTimer.scheduleAtFixedRate(new TimerTask() {

643

@Override

644

public void run() {

645

try {

646

// Periodic check to keep connection alive

647

if (store.isConnected()) {

648

folder.getMessageCount(); // No-op to keep connection active

649

} else {

650

System.out.println("Reconnecting to store...");

651

store.connect();

652

folder.open(Folder.READ_WRITE);

653

}

654

} catch (MessagingException e) {

655

System.err.println("Keep-alive check failed: " + e.getMessage());

656

}

657

}

658

}, 60000, 60000); // Check every minute

659

660

// Main event loop

661

try {

662

System.out.println("Mail monitoring started. Press Ctrl+C to stop.");

663

Thread.currentThread().join(); // Keep main thread alive

664

} catch (InterruptedException e) {

665

Thread.currentThread().interrupt();

666

}

667

}

668

}

669

```

670

671

## Event-Driven Mail Client Example

672

673

```java

674

public class EventDrivenMailClient {

675

private Store store;

676

private Folder inbox;

677

private List<Message> pendingMessages = new ArrayList<>();

678

679

public void startClient(Session session) throws MessagingException {

680

setupConnection(session);

681

setupEventHandlers();

682

startMessageProcessing();

683

}

684

685

private void setupConnection(Session session) throws MessagingException {

686

store = session.getStore("imap");

687

store.connect();

688

689

inbox = store.getFolder("INBOX");

690

inbox.open(Folder.READ_WRITE);

691

}

692

693

private void setupEventHandlers() {

694

// Handle new messages

695

inbox.addMessageCountListener(new MessageCountAdapter() {

696

@Override

697

public void messagesAdded(MessageCountEvent e) {

698

synchronized (pendingMessages) {

699

Collections.addAll(pendingMessages, e.getMessages());

700

pendingMessages.notifyAll();

701

}

702

}

703

});

704

705

// Handle connection issues

706

store.addConnectionListener(new ConnectionAdapter() {

707

@Override

708

public void disconnected(ConnectionEvent e) {

709

System.err.println("Connection lost! Attempting to reconnect...");

710

reconnect();

711

}

712

});

713

714

// Handle message changes

715

inbox.addMessageChangedListener(e -> {

716

try {

717

Message msg = e.getMessage();

718

System.out.println("Message updated: " + msg.getSubject());

719

} catch (MessagingException ex) {

720

System.err.println("Error handling message change: " + ex.getMessage());

721

}

722

});

723

}

724

725

private void startMessageProcessing() {

726

Thread processingThread = new Thread(() -> {

727

while (!Thread.currentThread().isInterrupted()) {

728

try {

729

synchronized (pendingMessages) {

730

while (pendingMessages.isEmpty()) {

731

pendingMessages.wait();

732

}

733

734

Message msg = pendingMessages.remove(0);

735

processMessage(msg);

736

}

737

} catch (InterruptedException e) {

738

Thread.currentThread().interrupt();

739

break;

740

} catch (Exception e) {

741

System.err.println("Error processing message: " + e.getMessage());

742

}

743

}

744

});

745

746

processingThread.setDaemon(true);

747

processingThread.start();

748

}

749

750

private void processMessage(Message msg) throws MessagingException {

751

System.out.println("Processing new message: " + msg.getSubject());

752

753

// Auto-reply to urgent messages

754

if (isUrgent(msg)) {

755

sendAutoReply(msg);

756

}

757

758

// Archive old messages automatically

759

if (isOld(msg)) {

760

archiveMessage(msg);

761

}

762

763

// Mark as processed

764

msg.setFlag(Flags.Flag.SEEN, true);

765

}

766

767

private boolean isUrgent(Message msg) throws MessagingException {

768

String subject = msg.getSubject();

769

return subject != null && (subject.contains("URGENT") || subject.contains("ASAP"));

770

}

771

772

private boolean isOld(Message msg) throws MessagingException {

773

Date received = msg.getReceivedDate();

774

if (received == null) return false;

775

776

Calendar cal = Calendar.getInstance();

777

cal.add(Calendar.MONTH, -6);

778

return received.before(cal.getTime());

779

}

780

781

private void sendAutoReply(Message msg) {

782

System.out.println("Sending auto-reply to urgent message");

783

// Implementation for auto-reply

784

}

785

786

private void archiveMessage(Message msg) throws MessagingException {

787

System.out.println("Archiving old message");

788

// Move to archive folder

789

Folder archive = store.getFolder("Archive");

790

if (!archive.exists()) {

791

archive.create(Folder.HOLDS_MESSAGES);

792

}

793

archive.open(Folder.READ_WRITE);

794

795

Message[] msgs = {msg};

796

inbox.copyMessages(msgs, archive);

797

msg.setFlag(Flags.Flag.DELETED, true);

798

799

archive.close(false);

800

}

801

802

private void reconnect() {

803

try {

804

Thread.sleep(5000); // Wait before reconnecting

805

if (!store.isConnected()) {

806

store.connect();

807

}

808

if (!inbox.isOpen()) {

809

inbox.open(Folder.READ_WRITE);

810

}

811

System.out.println("Reconnected successfully");

812

} catch (Exception e) {

813

System.err.println("Reconnection failed: " + e.getMessage());

814

}

815

}

816

817

public void shutdown() {

818

try {

819

if (inbox != null && inbox.isOpen()) {

820

inbox.close();

821

}

822

if (store != null && store.isConnected()) {

823

store.close();

824

}

825

} catch (MessagingException e) {

826

System.err.println("Error during shutdown: " + e.getMessage());

827

}

828

}

829

}

830

```

831

832

This comprehensive event handling system allows for reactive, event-driven mail applications that can respond to real-time changes in mail stores, handle connection issues gracefully, and provide rich user experiences with immediate feedback on mail operations.