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

message-search-filtering.mddocs/

0

# Message Search and Filtering

1

2

Message search and filtering provides comprehensive capabilities for querying messages based on various criteria including content, headers, dates, flags, and addresses with support for logical operations.

3

4

## Search Foundation

5

6

The SearchTerm abstract class forms the foundation of Jakarta Mail's search system.

7

8

```java { .api }

9

public abstract class SearchTerm implements Serializable {

10

// Core search method - must be implemented by all search terms

11

public abstract boolean match(Message msg);

12

13

// Object operations

14

public boolean equals(Object obj);

15

public int hashCode();

16

}

17

```

18

19

All search operations are performed by implementing the `match()` method that tests whether a message satisfies the search criteria.

20

21

## String-Based Search Terms

22

23

### Base String Search

24

25

```java { .api }

26

public abstract class StringTerm extends SearchTerm {

27

protected String pattern;

28

protected boolean ignoreCase;

29

30

// Constructors

31

protected StringTerm(String pattern);

32

protected StringTerm(String pattern, boolean ignoreCase);

33

34

// Accessors

35

public String getPattern();

36

public boolean getIgnoreCase();

37

}

38

```

39

40

### Content Search Terms

41

42

```java { .api }

43

// Search message body content

44

public final class BodyTerm extends StringTerm {

45

public BodyTerm(String pattern);

46

public BodyTerm(String pattern, boolean ignoreCase);

47

}

48

49

// Search subject line

50

public final class SubjectTerm extends StringTerm {

51

public SubjectTerm(String pattern);

52

public SubjectTerm(String pattern, boolean ignoreCase);

53

}

54

55

// Search specific header

56

public final class HeaderTerm extends StringTerm {

57

public HeaderTerm(String headerName, String pattern);

58

public HeaderTerm(String headerName, String pattern, boolean ignoreCase);

59

60

public String getHeaderName();

61

}

62

63

// Search Message-ID header

64

public final class MessageIDTerm extends StringTerm {

65

public MessageIDTerm(String msgid);

66

}

67

```

68

69

### String Search Usage Example

70

71

```java

72

import jakarta.mail.search.*;

73

import jakarta.mail.*;

74

75

// Search for messages containing "urgent" in body (case-insensitive)

76

SearchTerm bodySearch = new BodyTerm("urgent", true);

77

Message[] urgentMessages = folder.search(bodySearch);

78

79

// Search by subject

80

SearchTerm subjectSearch = new SubjectTerm("Meeting");

81

Message[] meetingMessages = folder.search(subjectSearch);

82

83

// Search specific header

84

SearchTerm headerSearch = new HeaderTerm("X-Priority", "1");

85

Message[] highPriorityMessages = folder.search(headerSearch);

86

87

// Search by Message-ID

88

SearchTerm messageIdSearch = new MessageIDTerm("<12345@example.com>");

89

Message[] specificMessage = folder.search(messageIdSearch);

90

91

// Case-sensitive body search

92

SearchTerm caseSensitiveSearch = new BodyTerm("CONFIDENTIAL", false);

93

Message[] confidentialMessages = folder.search(caseSensitiveSearch);

94

```

95

96

## Address-Based Search Terms

97

98

### Address Object Search

99

100

```java { .api }

101

public abstract class AddressTerm extends SearchTerm {

102

protected Address address;

103

104

// Constructor

105

protected AddressTerm(Address address);

106

107

// Accessor

108

public Address getAddress();

109

}

110

111

// Search sender addresses (Address objects)

112

public final class FromTerm extends AddressTerm {

113

public FromTerm(Address address);

114

}

115

116

// Search recipient addresses (Address objects)

117

public final class RecipientTerm extends AddressTerm {

118

public RecipientTerm(Message.RecipientType type, Address address);

119

120

public Message.RecipientType getRecipientType();

121

}

122

```

123

124

### Address String Search

125

126

```java { .api }

127

public abstract class AddressStringTerm extends StringTerm {

128

// Constructor

129

protected AddressStringTerm(String pattern);

130

protected AddressStringTerm(String pattern, boolean ignoreCase);

131

}

132

133

// Search sender addresses (string pattern)

134

public final class FromStringTerm extends AddressStringTerm {

135

public FromStringTerm(String pattern);

136

public FromStringTerm(String pattern, boolean ignoreCase);

137

}

138

139

// Search recipient addresses (string pattern)

140

public final class RecipientStringTerm extends AddressStringTerm {

141

public RecipientStringTerm(Message.RecipientType type, String pattern);

142

public RecipientStringTerm(Message.RecipientType type, String pattern, boolean ignoreCase);

143

144

public Message.RecipientType getRecipientType();

145

}

146

```

147

148

### Address Search Usage Example

149

150

```java

151

import jakarta.mail.search.*;

152

import jakarta.mail.internet.*;

153

154

// Search by exact sender address

155

InternetAddress senderAddr = new InternetAddress("boss@company.com");

156

SearchTerm fromSearch = new FromTerm(senderAddr);

157

Message[] fromBoss = folder.search(fromSearch);

158

159

// Search by sender address pattern (string)

160

SearchTerm fromStringSearch = new FromStringTerm("@company.com");

161

Message[] fromCompany = folder.search(fromStringSearch);

162

163

// Search by recipient (TO addresses)

164

SearchTerm toSearch = new RecipientStringTerm(Message.RecipientType.TO, "team@company.com");

165

Message[] toTeam = folder.search(toSearch);

166

167

// Search by CC recipients

168

SearchTerm ccSearch = new RecipientStringTerm(Message.RecipientType.CC, "@department.com");

169

Message[] ccDepartment = folder.search(ccSearch);

170

171

// Case-insensitive address search

172

SearchTerm caseInsensitiveSearch = new FromStringTerm("MANAGER", true);

173

Message[] fromManager = folder.search(caseInsensitiveSearch);

174

```

175

176

## Date-Based Search Terms

177

178

### Base Date Search

179

180

```java { .api }

181

public abstract class DateTerm extends ComparisonTerm {

182

protected Date date;

183

184

// Constructor

185

protected DateTerm(int comparison, Date date);

186

187

// Accessor

188

public Date getDate();

189

}

190

```

191

192

### Date Search Terms

193

194

```java { .api }

195

// Search by received date

196

public final class ReceivedDateTerm extends DateTerm {

197

public ReceivedDateTerm(int comparison, Date date);

198

}

199

200

// Search by sent date

201

public final class SentDateTerm extends DateTerm {

202

public SentDateTerm(int comparison, Date date);

203

}

204

```

205

206

### Comparison Operators

207

208

```java { .api }

209

public abstract class ComparisonTerm extends SearchTerm {

210

// Comparison constants

211

public static final int LE = 1; // Less than or equal

212

public static final int LT = 2; // Less than

213

public static final int EQ = 3; // Equal

214

public static final int NE = 4; // Not equal

215

public static final int GT = 5; // Greater than

216

public static final int GE = 6; // Greater than or equal

217

218

protected int comparison;

219

220

// Constructor

221

protected ComparisonTerm(int comparison);

222

223

// Accessor

224

public int getComparison();

225

}

226

```

227

228

### Date Search Usage Example

229

230

```java

231

import jakarta.mail.search.*;

232

import java.util.Date;

233

import java.util.Calendar;

234

235

// Search for messages received today

236

Calendar today = Calendar.getInstance();

237

today.set(Calendar.HOUR_OF_DAY, 0);

238

today.set(Calendar.MINUTE, 0);

239

today.set(Calendar.SECOND, 0);

240

today.set(Calendar.MILLISECOND, 0);

241

242

SearchTerm todaySearch = new ReceivedDateTerm(ComparisonTerm.GE, today.getTime());

243

Message[] todayMessages = folder.search(todaySearch);

244

245

// Search for messages sent last week

246

Calendar weekAgo = Calendar.getInstance();

247

weekAgo.add(Calendar.DAY_OF_YEAR, -7);

248

SearchTerm lastWeekSearch = new SentDateTerm(ComparisonTerm.GE, weekAgo.getTime());

249

Message[] lastWeekMessages = folder.search(lastWeekSearch);

250

251

// Search for messages received between two dates

252

Calendar startDate = Calendar.getInstance();

253

startDate.add(Calendar.DAY_OF_YEAR, -30);

254

Calendar endDate = Calendar.getInstance();

255

endDate.add(Calendar.DAY_OF_YEAR, -1);

256

257

SearchTerm dateRange = new AndTerm(

258

new ReceivedDateTerm(ComparisonTerm.GE, startDate.getTime()),

259

new ReceivedDateTerm(ComparisonTerm.LE, endDate.getTime())

260

);

261

Message[] rangeMessages = folder.search(dateRange);

262

263

// Search for messages sent exactly on a specific date

264

Calendar specificDate = Calendar.getInstance();

265

specificDate.set(2024, Calendar.JANUARY, 1);

266

SearchTerm exactDateSearch = new SentDateTerm(ComparisonTerm.EQ, specificDate.getTime());

267

Message[] exactDateMessages = folder.search(exactDateSearch);

268

```

269

270

## Numeric Search Terms

271

272

### Base Numeric Search

273

274

```java { .api }

275

public abstract class IntegerComparisonTerm extends ComparisonTerm {

276

protected int number;

277

278

// Constructor

279

protected IntegerComparisonTerm(int comparison, int number);

280

281

// Accessor

282

public int getNumber();

283

}

284

```

285

286

### Numeric Search Terms

287

288

```java { .api }

289

// Search by message number

290

public final class MessageNumberTerm extends IntegerComparisonTerm {

291

public MessageNumberTerm(int number);

292

public MessageNumberTerm(int comparison, int number);

293

}

294

295

// Search by message size

296

public final class SizeTerm extends IntegerComparisonTerm {

297

public SizeTerm(int comparison, int size);

298

}

299

```

300

301

### Numeric Search Usage Example

302

303

```java

304

import jakarta.mail.search.*;

305

306

// Search for large messages (over 1MB)

307

SearchTerm largeMessages = new SizeTerm(ComparisonTerm.GT, 1024 * 1024);

308

Message[] bigMessages = folder.search(largeMessages);

309

310

// Search for small messages (under 10KB)

311

SearchTerm smallMessages = new SizeTerm(ComparisonTerm.LT, 10 * 1024);

312

Message[] tinyMessages = folder.search(smallMessages);

313

314

// Search for specific message number

315

SearchTerm messageNumber = new MessageNumberTerm(100);

316

Message[] specificNumber = folder.search(messageNumber);

317

318

// Search for messages in a range of numbers

319

SearchTerm numberRange = new AndTerm(

320

new MessageNumberTerm(ComparisonTerm.GE, 50),

321

new MessageNumberTerm(ComparisonTerm.LE, 100)

322

);

323

Message[] numberRangeMessages = folder.search(numberRange);

324

```

325

326

## Flag-Based Search Terms

327

328

### Flag Search

329

330

```java { .api }

331

public final class FlagTerm extends SearchTerm {

332

// Constructors

333

public FlagTerm(Flags flags, boolean set);

334

335

// Accessors

336

public Flags getFlags();

337

public boolean getTestSet();

338

}

339

```

340

341

### Flag Search Usage Example

342

343

```java

344

import jakarta.mail.search.*;

345

import jakarta.mail.*;

346

347

// Search for unread messages

348

Flags unreadFlags = new Flags(Flags.Flag.SEEN);

349

SearchTerm unreadSearch = new FlagTerm(unreadFlags, false);

350

Message[] unreadMessages = folder.search(unreadSearch);

351

352

// Search for flagged messages

353

Flags flaggedFlags = new Flags(Flags.Flag.FLAGGED);

354

SearchTerm flaggedSearch = new FlagTerm(flaggedFlags, true);

355

Message[] flaggedMessages = folder.search(flaggedSearch);

356

357

// Search for deleted messages

358

Flags deletedFlags = new Flags(Flags.Flag.DELETED);

359

SearchTerm deletedSearch = new FlagTerm(deletedFlags, true);

360

Message[] deletedMessages = folder.search(deletedSearch);

361

362

// Search for draft messages

363

Flags draftFlags = new Flags(Flags.Flag.DRAFT);

364

SearchTerm draftSearch = new FlagTerm(draftFlags, true);

365

Message[] draftMessages = folder.search(draftSearch);

366

367

// Search for answered messages

368

Flags answeredFlags = new Flags(Flags.Flag.ANSWERED);

369

SearchTerm answeredSearch = new FlagTerm(answeredFlags, true);

370

Message[] answeredMessages = folder.search(answeredSearch);

371

372

// Search for recent messages

373

Flags recentFlags = new Flags(Flags.Flag.RECENT);

374

SearchTerm recentSearch = new FlagTerm(recentFlags, true);

375

Message[] recentMessages = folder.search(recentSearch);

376

377

// Search for custom user flags

378

Flags customFlags = new Flags();

379

customFlags.add("Important");

380

SearchTerm customSearch = new FlagTerm(customFlags, true);

381

Message[] importantMessages = folder.search(customSearch);

382

```

383

384

## Logical Operators

385

386

### Logical AND

387

388

```java { .api }

389

public final class AndTerm extends SearchTerm {

390

// Constructors

391

public AndTerm(SearchTerm t1, SearchTerm t2);

392

public AndTerm(SearchTerm[] terms);

393

394

// Accessor

395

public SearchTerm[] getTerms();

396

}

397

```

398

399

### Logical OR

400

401

```java { .api }

402

public final class OrTerm extends SearchTerm {

403

// Constructors

404

public OrTerm(SearchTerm t1, SearchTerm t2);

405

public OrTerm(SearchTerm[] terms);

406

407

// Accessor

408

public SearchTerm[] getTerms();

409

}

410

```

411

412

### Logical NOT

413

414

```java { .api }

415

public final class NotTerm extends SearchTerm {

416

// Constructor

417

public NotTerm(SearchTerm t);

418

419

// Accessor

420

public SearchTerm getTerm();

421

}

422

```

423

424

### Logical Operators Usage Example

425

426

```java

427

import jakarta.mail.search.*;

428

429

// Complex search: Unread messages from specific sender

430

SearchTerm complexSearch = new AndTerm(

431

new FlagTerm(new Flags(Flags.Flag.SEEN), false),

432

new FromStringTerm("important@company.com")

433

);

434

Message[] unreadFromImportant = folder.search(complexSearch);

435

436

// Multiple AND conditions

437

SearchTerm multipleAnd = new AndTerm(new SearchTerm[] {

438

new SubjectTerm("Meeting"),

439

new FromStringTerm("@company.com"),

440

new ReceivedDateTerm(ComparisonTerm.GE, weekAgo.getTime())

441

});

442

Message[] complexResults = folder.search(multipleAnd);

443

444

// OR search: Messages from multiple senders

445

SearchTerm multiSenderSearch = new OrTerm(

446

new FromStringTerm("boss@company.com"),

447

new FromStringTerm("manager@company.com")

448

);

449

Message[] fromBossOrManager = folder.search(multiSenderSearch);

450

451

// NOT search: Messages not from specific domain

452

SearchTerm notFromSpam = new NotTerm(

453

new FromStringTerm("@spam.com")

454

);

455

Message[] nonSpamMessages = folder.search(notFromSpam);

456

457

// Complex nested logic: (urgent OR important) AND not read AND from company

458

SearchTerm urgentOrImportant = new OrTerm(

459

new SubjectTerm("urgent"),

460

new SubjectTerm("important")

461

);

462

463

SearchTerm unreadAndFromCompany = new AndTerm(

464

new FlagTerm(new Flags(Flags.Flag.SEEN), false),

465

new FromStringTerm("@company.com")

466

);

467

468

SearchTerm finalSearch = new AndTerm(urgentOrImportant, unreadAndFromCompany);

469

Message[] complexNestedResults = folder.search(finalSearch);

470

```

471

472

## Advanced Search Patterns

473

474

### Time Range Searches

475

476

```java

477

// Messages from last 24 hours

478

Calendar yesterday = Calendar.getInstance();

479

yesterday.add(Calendar.DAY_OF_YEAR, -1);

480

SearchTerm last24Hours = new ReceivedDateTerm(ComparisonTerm.GE, yesterday.getTime());

481

482

// Messages from this month

483

Calendar startOfMonth = Calendar.getInstance();

484

startOfMonth.set(Calendar.DAY_OF_MONTH, 1);

485

startOfMonth.set(Calendar.HOUR_OF_DAY, 0);

486

startOfMonth.set(Calendar.MINUTE, 0);

487

startOfMonth.set(Calendar.SECOND, 0);

488

SearchTerm thisMonth = new ReceivedDateTerm(ComparisonTerm.GE, startOfMonth.getTime());

489

490

// Messages older than 30 days

491

Calendar thirtyDaysAgo = Calendar.getInstance();

492

thirtyDaysAgo.add(Calendar.DAY_OF_YEAR, -30);

493

SearchTerm oldMessages = new ReceivedDateTerm(ComparisonTerm.LT, thirtyDaysAgo.getTime());

494

```

495

496

### Content and Metadata Searches

497

498

```java

499

// High priority messages

500

SearchTerm highPriority = new OrTerm(new SearchTerm[] {

501

new HeaderTerm("X-Priority", "1"),

502

new HeaderTerm("Priority", "urgent"),

503

new SubjectTerm("URGENT"),

504

new SubjectTerm("IMPORTANT")

505

});

506

507

// Attachment searches (size-based heuristic)

508

SearchTerm hasAttachments = new SizeTerm(ComparisonTerm.GT, 50 * 1024); // > 50KB

509

510

// Meeting-related messages

511

SearchTerm meetingMessages = new OrTerm(new SearchTerm[] {

512

new SubjectTerm("meeting"),

513

new SubjectTerm("conference"),

514

new SubjectTerm("call"),

515

new BodyTerm("calendar")

516

});

517

```

518

519

### Mailbox Management Searches

520

521

```java

522

// Messages to clean up (old, read, not flagged)

523

SearchTerm cleanupCandidates = new AndTerm(new SearchTerm[] {

524

new ReceivedDateTerm(ComparisonTerm.LT, thirtyDaysAgo.getTime()),

525

new FlagTerm(new Flags(Flags.Flag.SEEN), true),

526

new FlagTerm(new Flags(Flags.Flag.FLAGGED), false)

527

});

528

529

// Important messages to preserve

530

SearchTerm importantToKeep = new OrTerm(new SearchTerm[] {

531

new FlagTerm(new Flags(Flags.Flag.FLAGGED), true),

532

new SubjectTerm("contract"),

533

new SubjectTerm("invoice"),

534

new FromStringTerm("legal@")

535

});

536

537

// Spam-like messages

538

SearchTerm potentialSpam = new OrTerm(new SearchTerm[] {

539

new SubjectTerm("free"),

540

new SubjectTerm("urgent action required"),

541

new BodyTerm("click here"),

542

new FromStringTerm("noreply@")

543

});

544

```

545

546

## Search Performance Optimization

547

548

### Using Search with Fetch Profiles

549

550

```java

551

// Optimize search performance with fetch profiles

552

FetchProfile fetchProfile = new FetchProfile();

553

fetchProfile.add(FetchProfile.Item.ENVELOPE);

554

fetchProfile.add(FetchProfile.Item.FLAGS);

555

556

// Perform search

557

Message[] results = folder.search(searchTerm);

558

559

// Fetch needed data in bulk

560

folder.fetch(results, fetchProfile);

561

562

// Now access is optimized

563

for (Message message : results) {

564

// These accesses are now efficient

565

System.out.println("From: " + Arrays.toString(message.getFrom()));

566

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

567

System.out.println("Flags: " + message.getFlags());

568

}

569

```

570

571

### Search on Subsets

572

573

```java

574

// Search within a specific range first

575

Message[] recentMessages = folder.getMessages(folder.getMessageCount() - 100, folder.getMessageCount());

576

577

// Then search within that subset

578

Message[] searchResults = folder.search(searchTerm, recentMessages);

579

```

580

581

## Search Exception Handling

582

583

```java { .api }

584

public class SearchException extends MessagingException {

585

public SearchException();

586

public SearchException(String message);

587

public SearchException(String message, Exception e);

588

}

589

```

590

591

### Search Error Handling Example

592

593

```java

594

try {

595

Message[] results = folder.search(complexSearchTerm);

596

System.out.println("Found " + results.length + " messages");

597

} catch (SearchException e) {

598

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

599

// Fallback to simpler search or manual filtering

600

} catch (MessagingException e) {

601

System.err.println("Messaging error during search: " + e.getMessage());

602

}

603

```