Email Metadata Queries
Content: Email Metadata Queries
User Intent
"How do I query emails by sender, subject, labels, etc.?"
Operation
SDK Method:
queryContents()with email-specific patternsGraphQL:
queryContentsqueryEntity Type: Content (type: EMAIL)
Common Use Cases: Find emails by sender, filter by labels, search by subject, date range queries
Email Metadata Structure
Emails have rich metadata captured in the email field:
interface EmailMetadata {
identifier: string; // Message-ID
threadIdentifier: string; // Thread ID
subject: string;
from: PersonReference[];
to: PersonReference[];
cc: PersonReference[];
bcc: PersonReference[];
labels: string[]; // Gmail labels
sensitivity: MailSensitivity;
priority: MailPriority;
importance: MailImportance;
attachmentCount: number;
unsubscribeUrl: string;
publicationName: string;
publicationUrl: string;
}TypeScript (Canonical)
import { Graphlit } from 'graphlit-client';
import { ContentTypes, SearchTypes } from 'graphlit-client/dist/generated/graphql-types';
const graphlit = new Graphlit();
// Query all emails
const allEmails = await graphlit.queryContents({
filter: {
types: [ContentTypes.Email]
}
});
// Search emails by keyword
const searchEmails = await graphlit.queryContents({
search: "quarterly report",
filter: {
types: [ContentTypes.Email]
}
});
// Recent emails
const recentEmails = await graphlit.queryContents({
filter: {
types: [ContentTypes.Email],
createdInLast: 'P7D' // Last 7 days
}
});
// Emails from specific sender (keyword search)
const fromSender = await graphlit.queryContents({
search: "[email protected]",
searchType: SearchTypes.Keyword,
filter: {
types: [ContentTypes.Email]
}
});
// Emails with attachments
const withAttachments = await graphlit.queryContents({
filter: {
types: [ContentTypes.Email]
}
});
// Filter client-side for attachments
const hasAttachments = withAttachments.contents.results.filter(
email => email.email && email.email.attachmentCount > 0
);
console.log(`Found ${hasAttachments.length} emails with attachments`);Query Patterns
1. Find by Sender
// Search by sender email
const fromKirk = await graphlit.queryContents({
search: "[email protected]",
searchType: SearchTypes.Keyword,
filter: {
types: [ContentTypes.Email]
}
});
// Search by sender name
const fromName = await graphlit.queryContents({
search: "Kirk Marple",
searchType: SearchTypes.Keyword,
filter: {
types: [ContentTypes.Email]
}
});
// Access sender details
fromKirk.contents.results.forEach(email => {
if (email.email && email.email.from) {
console.log(`From: ${email.email.from[0].name} <${email.email.from[0].email}>`);
console.log(`Subject: ${email.email.subject}`);
}
});2. Find by Subject
// Search in subject
const subjectSearch = await graphlit.queryContents({
search: "quarterly earnings report",
filter: {
types: [ContentTypes.Email]
}
});
// Exact subject match
const exactSubject = await graphlit.queryContents({
search: '"Q4 2024 Earnings"',
searchType: SearchTypes.Keyword,
filter: {
types: [ContentTypes.Email]
}
});3. Find by Recipient
// Search by recipient
const toMaria = await graphlit.queryContents({
search: "[email protected]",
searchType: SearchTypes.Keyword,
filter: {
types: [ContentTypes.Email]
}
});
// Check if specific person is in TO/CC/BCC
const allEmails = await graphlit.queryContents({
filter: {
types: [ContentTypes.Email]
}
});
const toRecipient = allEmails.contents.results.filter(email => {
if (!email.email) return false;
const allRecipients = [
...(email.email.to || []),
...(email.email.cc || []),
...(email.email.bcc || [])
];
return allRecipients.some(r => r.email === "[email protected]");
});
console.log(`Found ${toRecipient.length} emails to [email protected]`);4. Filter by Labels (Gmail)
// Get emails with specific label
const emails = await graphlit.queryContents({
filter: {
types: [ContentTypes.Email]
}
});
// Filter by Gmail label
const important = emails.contents.results.filter(email =>
email.email?.labels?.includes('IMPORTANT')
);
const unread = emails.contents.results.filter(email =>
email.email?.labels?.includes('UNREAD')
);
const starred = emails.contents.results.filter(email =>
email.email?.labels?.includes('STARRED')
);
console.log(`Important: ${important.length}`);
console.log(`Unread: ${unread.length}`);
console.log(`Starred: ${starred.length}`);5. Date Range Queries
// Emails from last month
const lastMonth = await graphlit.queryContents({
filter: {
types: [ContentTypes.Email],
createdInLast: 'P30D'
}
});
// Emails in specific date range
const dateRange = await graphlit.queryContents({
filter: {
types: [ContentTypes.Email],
creationDateRange: {
from: '2024-01-01T00:00:00Z',
to: '2024-12-31T23:59:59Z'
}
}
});
// Q4 2024 emails
const q4 = await graphlit.queryContents({
filter: {
types: [ContentTypes.Email],
creationDateRange: {
from: '2024-10-01',
to: '2024-12-31'
}
}
});6. Thread Queries
// Get all emails
const emails = await graphlit.queryContents({
filter: {
types: [ContentTypes.Email]
},
limit: 100
});
// Group by thread
const threads = new Map<string, any[]>();
emails.contents.results.forEach(email => {
if (email.email?.threadIdentifier) {
const threadId = email.email.threadIdentifier;
if (!threads.has(threadId)) {
threads.set(threadId, []);
}
threads.get(threadId)?.push(email);
}
});
console.log(`Found ${threads.size} email threads`);
// Find longest threads
const sortedThreads = Array.from(threads.entries())
.sort((a, b) => b[1].length - a[1].length);
console.log('\nTop 5 longest threads:');
sortedThreads.slice(0, 5).forEach(([threadId, emails]) => {
console.log(`Thread ${threadId}: ${emails.length} emails`);
console.log(` Subject: ${emails[0].email?.subject}`);
});7. With Attachments
// Query all emails
const emails = await graphlit.queryContents({
filter: {
types: [ContentTypes.Email]
}
});
// Filter by attachment count
const withAttachments = emails.contents.results.filter(email =>
email.email && email.email.attachmentCount > 0
);
const multipleAttachments = emails.contents.results.filter(email =>
email.email && email.email.attachmentCount > 1
);
console.log(`With attachments: ${withAttachments.length}`);
console.log(`Multiple attachments: ${multipleAttachments.length}`);
// List emails with most attachments
const sorted = emails.contents.results
.filter(email => email.email && email.email.attachmentCount > 0)
.sort((a, b) => (b.email?.attachmentCount || 0) - (a.email?.attachmentCount || 0));
console.log('\nTop 5 emails by attachment count:');
sorted.slice(0, 5).forEach(email => {
console.log(`${email.name}: ${email.email?.attachmentCount} attachments`);
});8. Newsletter Detection
// Find newsletters
const emails = await graphlit.queryContents({
filter: {
types: [ContentTypes.Email]
}
});
const newsletters = emails.contents.results.filter(email =>
email.email?.publicationName || email.email?.unsubscribeUrl
);
console.log(`Found ${newsletters.length} newsletters`);
// Group by publication
const byPublication = new Map<string, number>();
newsletters.forEach(email => {
const pub = email.email?.publicationName || 'Unknown';
byPublication.set(pub, (byPublication.get(pub) || 0) + 1);
});
console.log('\nNewsletters by publication:');
Array.from(byPublication.entries())
.sort((a, b) => b[1] - a[1])
.forEach(([pub, count]) => {
console.log(` ${pub}: ${count}`);
});Sample Reference
Graphlit_2024_09_07_Locate_Google_Emails_by_Person.ipynbGraphlit_2024_12_09_Locate_Microsoft_Emails_by_Organization.ipynb
Query emails
emails = await graphlit.queryContents( filter=ContentFilterInput( types=[ContentTypes.Email] ) )
By sender
from_kirk = await graphlit.queryContents( search="[email protected]", search_type=SearchTypes.Keyword, filter=ContentFilterInput( types=[ContentTypes.Email] ) )
Recent emails
recent = await graphlit.queryContents( filter=ContentFilterInput( types=[ContentTypes.Email], created_in_last='P7D' ) )
Access metadata
for email in emails.contents.results: if email.email: print(f"From: {email.email.from_[0].email}") print(f"Subject: {email.email.subject}")
**C#**:
```csharp
using Graphlit;
var client = new Graphlit();
// Query emails
var emails = await graphlit.QueryContents(new ContentFilter
{
Types = new[] { ContentTypes.Email }
});
// By sender
var fromKirk = await graphlit.QueryContents(new ContentFilter
{
Search = "[email protected]",
SearchType = SearchKeyword,
Filter = new ContentCriteria
{
Types = new[] { ContentTypes.Email }
}
});
// Recent emails
var recent = await graphlit.QueryContents(new ContentFilter
{
Filter = new ContentCriteria
{
Types = new[] { ContentTypes.Email },
CreatedInLast = "P7D"
}
});
// Access metadata
foreach (var email in emails.Contents.Results)
{
if (email.Email != null)
{
Console.WriteLine($"From: {email.Email.From[0].Email}");
Console.WriteLine($"Subject: {email.Email.Subject}");
}
}Developer Hints
Email Addresses are Searchable
// Keyword search works for email addresses
const results = await graphlit.queryContents({
search: "[email protected]",
searchType: SearchTypes.Keyword,
filter: { types: [ContentTypes.Email] }
});Labels are Gmail-Specific
// Gmail uses labels
email.email?.labels // ["INBOX", "IMPORTANT", "UNREAD"]
// Outlook uses folders (not in labels field)
// Check feed type to determine sourceThread Detection
// Emails with same threadIdentifier are part of same conversation
if (email.email?.threadIdentifier) {
console.log(`Part of thread: ${email.email.threadIdentifier}`);
}Common Issues & Solutions
Issue: Can't filter by specific label Solution: Query all emails, filter client-side
const all = await graphlit.queryContents({
filter: { types: [ContentTypes.Email] }
});
const important = all.contents.results.filter(
e => e.email?.labels?.includes('IMPORTANT')
);Issue: Want emails TO a specific person Solution: Search by email or filter client-side
// Keyword search
await graphlit.queryContents({
search: "[email protected]",
filter: { types: [ContentTypes.Email] }
});
// Or filter after query
const all = await graphlit.queryContents({
filter: { types: [ContentTypes.Email] }
});
const toMaria = all.contents.results.filter(e =>
e.email?.to?.some(r => r.email === "[email protected]")
);Issue: Need to count emails by sender Solution: Query and aggregate client-side
const emails = await graphlit.queryContents({
filter: { types: [ContentTypes.Email] }
});
const bySender = new Map<string, number>();
emails.contents.results.forEach(email => {
const sender = email.email?.from[0]?.email || 'unknown';
bySender.set(sender, (bySender.get(sender) || 0) + 1);
});Production Example
async function analyzeEmails() {
console.log('\n=== EMAIL ANALYSIS ===\n');
// Get all emails
const emails = await graphlit.queryContents({
filter: {
types: [ContentTypes.Email],
createdInLast: 'P30D' // Last 30 days
},
limit: 500
});
console.log(`Total emails: ${emails.contents.results.length}`);
// Analyze senders
const senders = new Map<string, number>();
emails.contents.results.forEach(email => {
if (email.email?.from[0]) {
const sender = email.email.from[0].email;
senders.set(sender, (senders.get(sender) || 0) + 1);
}
});
console.log(`\nTop 10 senders:`);
Array.from(senders.entries())
.sort((a, b) => b[1] - a[1])
.slice(0, 10)
.forEach(([sender, count]) => {
console.log(` ${sender}: ${count} emails`);
});
// Attachment statistics
const withAttachments = emails.contents.results.filter(
e => e.email && e.email.attachmentCount > 0
);
console.log(`\nEmails with attachments: ${withAttachments.length} (${(withAttachments.length / emails.contents.results.length * 100).toFixed(1)}%)`);
// Thread analysis
const threads = new Map<string, any[]>();
emails.contents.results.forEach(email => {
if (email.email?.threadIdentifier) {
const tid = email.email.threadIdentifier;
if (!threads.has(tid)) threads.set(tid, []);
threads.get(tid)?.push(email);
}
});
console.log(`\nThreads: ${threads.size}`);
const threadLengths = Array.from(threads.values()).map(t => t.length);
const avgThreadLength = threadLengths.reduce((a, b) => a + b, 0) / threadLengths.length;
console.log(`Average thread length: ${avgThreadLength.toFixed(1)} emails`);
// Labels (Gmail)
const allLabels = new Set<string>();
emails.contents.results.forEach(email => {
email.email?.labels?.forEach(label => allLabels.add(label));
});
console.log(`\nUnique labels: ${allLabels.size}`);
console.log(`Labels: ${Array.from(allLabels).join(', ')}`);
// Newsletters
const newsletters = emails.contents.results.filter(
e => e.email?.publicationName
);
console.log(`\nNewsletters: ${newsletters.length}`);
}
await analyzeEmails();Last updated
Was this helpful?