OpenJDK Mail Search is a collection of tools for locating, indexing, and searching OpenJDK mailing list records.
The goal is to produce a website with a search interface that provides access to the entire mailing list history for targeted lists.
Searches are based on (1) exact-match for mail author name and email and (2) phrase-query for mail subject and body.
This results in fast, predictable search outcomes tailored for simple code-related queries.
https://openjdk.barlasgarden.com
Thank you to @bowbahdoe for the Duke art and for other collaborations on this project.
Indexing functionality resides in the indexer.py module. The module contain an index function
that accepts mailing list record fields and returns a list of terms.
There are 4 mailing list record fields that are indexed: (1) author, (2) email, (3) subject, and (4) body.
They each pass through this indexing pipeline and contribute to the final terms result.
Mail records that match a stop-function are not indexed at all.
Mail body lines that match stop-line exclusion rules are removed from the input prior to tokenization.
For example, quoted text lines \W*> are not indexed.
The input is split on whitespace and converted to lowercase.
Project Panama→project,panama
Prior to normalization, tokens longer than 100 characters and tokens with stop-prefixes (e.g. https://) are excluded.
Tokens are stripped of non-word characters defined by [^\w+#].
snake_case→snake_case(underscore kept)C++→c++(plus kept)C#→c#(hash kept)SSL-socket→sslsocket(hyphen removed)
Stop words are removed from the normalized tokens.
a, an, and, are, as, at, be, but, by, for, if, in, into, is, it, no,
not, of, on, or, such, that, the, their, then, there, these, they, this, to,
was, will, with
... This, is, an, outrage ...→... outrage ...
Tokens are arranged into terms, the final product of this pipeline.
Short, contiguous sequences of tokens are added as terms.
A word n-gram length of 3 is used for the mail body, and an n-gram length of 5 is used for the author, email, and subject.
Additionally, author, email, and subject all include the full normalized token list as a single phrase term.
... data, oriented, programming ...→
[data]
[data, oriented]
[data, oriented, programming]
[oriented]
[oriented, programming]
[programming]
High-frequency terms, such as [have], [should], and [i, think] are removed.
This stage runs after pre-filtering. It performs additional tokenization on words that contain structural delimiters.
Raw tokens are split on /, ., =, and ::.
All contiguous segment combinations are normalized, filtered, joined, and added as terms.
This makes strings like java.util.concurrent and org/example/Main discoverable in multiple ways.
A word n-gram length of 10 is used for code segments.
java.util.concurrent→
[java]
[javautil]
[javautilconcurrent]
[util]
[utilconcurrent]
[concurrent]
- Email is used as author if the author field doesn't exist in the mail record
- Git and Mercurial changeset emails are not indexed
- Quoted lines starting with
>are not indexed - Word n-gram length of 3 for mail body
- Word n-gram length of 5 for mail subject
- Word n-gram length of 10 for code segments
- Maximum token size of 100
- Maximum of 100 code segment terms
- Maximum of 2,500 terms per indexed mail record
These are the various tools in this repo:
seed.py- CLI tool for seeding mailing list indexserver.py- AWS Lambda API server for processing mailing list queriesupdater.py- AWS Lambda scheduled job for continuously updating indexesindex.html- static website with mailing list search interface
The website is deployed using a simple AWS stack:
- DynamoDB - indexes and metadata stored here
- S3 - static website content, including the search page
- CloudFront - website gateway with API lambda function attached
- Lambda - compute for API server and scheduled job
Attribute definitions:
termstring - search term, e.g.SSLSocketdatestring - fixed-width ISO-8601 date in UTC, e.g.2025-08-24T20:07:24Zliststring - mailing list name, e.g.net-devmonthstring - mailing list month, e.g.2025-Augustidstring - mail ID, e.g.027714authorstring - author name, e.g.Peter Parkerauthorkeystring - normalized author name, e.g.peterparkeremailstring - author email, e.g.peter.parker@marvel.comemailkeystring - normalized author email, e.g.peterparkermarvelcom
Tables:
openjdk-mail-terms- [PK]
p(short forlist_termpartition key)- Slash-delimited composition of
list,term - e.g.
net-dev/SSLSocket
- Slash-delimited composition of
- [SK]
s(short fordate_month_idsort key)- Slash-delimited composition of
date,month,id - e.g.
2025-08-24T20:07:24Z/2025-August/027714
- Slash-delimited composition of
- [GSI]
term_date- [PK]
t(short fortermpartition key) - [SK]
d(short fordatesort key
- [PK]
- [PK]
openjdk-mail-records- [PK]
list - [SK]
month_id- Slash-delimited composition of
month,id - e.g.
2025-August/027714
- Slash-delimited composition of
- [LSI]
list_date- [PK]
list - [SK]
date
- [PK]
- [LSI]
list_authorkey_date- [PK]
list - [SK]
authorkey_date- Slash-delimited composition of
authorkey,date - e.g.
peterparker/2025-08-24T20:07:24Z
- Slash-delimited composition of
- [PK]
- [LSI]
list_emailkey_date- [PK]
list - [SK]
emailkey_date- Slash-delimited composition of
emailkey,date - e.g.
peterparkermarvelcom/2025-08-24T20:07:24Z
- Slash-delimited composition of
- [PK]
- [GSI]
month_date- [PK]
month - [SK]
date
- [PK]
- [GSI]
authorkey_date- [PK]
authorkey - [SK]
date
- [PK]
- [GSI]
emailkey_date- [PK]
emailkey - [SK]
date
- [PK]
- [GSI]
datekey_date- [PK]
datekey - [SK]
date
- [PK]
- [PK]
openjdk-mail-checkpoints- [PK]
list
- [PK]
openjdk-mail-status- [PK]
pk
- [PK]
Full request/response details, schemas, and examples are in openapi.yaml (OpenAPI 3.0).
- Search mail in a list
GET /lists/{list}/mail/search?q={query}&order={asc|desc}&limit={limit}&cursor={cursor}&from={from}&to={to}
- Get latest mail for a list
GET /lists/{list}/mail?order={asc|desc}&limit={limit}&cursor={cursor}&from={from}&to={to}
- Get mail for a list by author name
GET /lists/{list}/mail/byauthor?author={author}&order={asc|desc}&limit={limit}&cursor={cursor}&from={from}&to={to}
- Get mail for a list by author email
GET /lists/{list}/mail/byemail?email={email}&order={asc|desc}&limit={limit}&cursor={cursor}&from={from}&to={to}
- Search mail across all lists
GET /mail/search?q={query}&order={asc|desc}&limit={limit}&cursor={cursor}&from={from}&to={to}
- Get mail across all lists by author name
GET /mail/byauthor?author={author}&order={asc|desc}&limit={limit}&cursor={cursor}&from={from}&to={to}
- Get mail across all lists by author email
GET /mail/byemail?email={email}&order={asc|desc}&limit={limit}&cursor={cursor}&from={from}&to={to}
- Get mail across all lists
GET /mail?order={asc|desc}&limit={limit}&cursor={cursor}&from={from}&to={to}
The mcp sub-project provides an MCP server for searching and browsing OpenJDK mailing list archives.
Below is an example with Cursor IDE. Add it via Settings → MCP and edit ~/.cursor/mcp.json; add an openjdk-mail entry under mcpServers:
"openjdk-mail": {
"command": "uv",
"args": [
"run",
"--project",
"/path/to/openjdk-mailing/mcp",
"--directory",
"/path/to/openjdk-mailing/mcp",
"python",
"mcp_server.py"
]
}
Replace /path/to/openjdk-mailing with your repo path (e.g. /Users/you/Code/openjdk-mailing).