Add advanced Outlook search and logging features

Introduces multiple search helper methods to the Outlook class, including sender/recipient/subject filters and date-based queries. Adds detailed logging for MAPI session management and folder selection. Implements ItemsFiltered for predicate-based filtering and refactors folder path resolution for improved robustness.
This commit is contained in:
Namhyeon, Go 2026-01-18 13:47:36 +09:00
parent 630495f243
commit 02ef05586e

View File

@ -237,19 +237,35 @@ function Outlook() {
this.open = function () {
try {
this.namespace.Logon("", "", false, false);
} catch (e) {}
console.info("Outlook MAPI session established");
} catch (e) {
// Already logged on / interactive session not required
console.warn("Outlook MAPI session already active or logon skipped");
}
this.selectFolder(Outlook.Folders.Inbox);
console.info("Outlook folder selected: Inbox");
return this;
};
this.close = function () {
this.items = null;
this.currentFolder = null;
try { this.namespace.Logoff(); } catch (e) {}
try {
this.namespace.Logoff();
console.info("Outlook MAPI session closed");
} catch (e) {
// Logoff may fail if Outlook manages the session
console.warn("Outlook MAPI session logoff skipped");
}
this.namespace = null;
this.application = null;
console.info("Outlook automation released");
};
this.selectFolder = function (folderIdOrPath) {
if (typeof folderIdOrPath === "number") {
this.currentFolder = this.namespace.GetDefaultFolder(folderIdOrPath);
@ -260,7 +276,7 @@ function Outlook() {
}
this.items = this.currentFolder.Items;
this.items.Sort("[ReceivedTime]", true);
this.items.Sort("[ReceivedTime]", true); // newest first
return this;
};
@ -280,9 +296,44 @@ function Outlook() {
};
this.createMail = function () {
var mail = this.application.CreateItem(0);
var mail = this.application.CreateItem(0); // 0 = olMailItem
return new Outlook.MailItem(mail);
};
// -----------------------------
// Search helpers
// -----------------------------
this.searchBySenderContains = function (keyword) {
return this.restrict(Outlook.Search.filters.senderContains(keyword));
};
this.searchByRecipientContains = function (keyword) {
return this.restrict(Outlook.Search.filters.recipientContains(keyword));
};
this.searchBySenderOrRecipientContains = function (keyword) {
var pre = this.restrict(Outlook.Search.filters.senderOrToCcBccContains(keyword));
return new Outlook.ItemsFiltered(pre, function (mailItem) {
return Outlook.Search.match.senderOrRecipientObjectContains(mailItem, keyword);
});
};
this.searchBySenderEmailEquals = function (email) {
return this.restrict(Outlook.Search.filters.senderEmailEquals(email));
};
this.searchUnread = function () {
return this.restrict("[Unread] = True");
};
this.searchSince = function (dateObj) {
return this.restrict(Outlook.Search.filters.receivedSince(dateObj));
};
this.searchSubjectContains = function (keyword) {
return this.restrict(Outlook.Search.filters.subjectContains(keyword));
};
}
Outlook.Folders = {
@ -297,15 +348,27 @@ Outlook.Folders = {
Outlook.MailItemClass = 43;
Outlook.resolveFolderPath = function (mapiNamespace, path) {
// path examples:
// - "Inbox\\SubFolder"
// - "Mailbox - Name\\Inbox\\SubFolder" (store root name)
var parts = path.split("\\");
var root = mapiNamespace.Folders.Item(1);
var cur = root;
var cur = null;
for (var i = 0; i < parts.length; i++) {
if (parts[i]) {
cur = cur.Folders.Item(parts[i]);
// If first segment matches a store root, start there; else start at default store root.
var stores = mapiNamespace.Folders;
for (var i = 1; i <= stores.Count; i++) {
var f = stores.Item(i);
if ((f.Name + "") === (parts[0] + "")) {
cur = f;
parts.shift();
break;
}
}
if (!cur) cur = stores.Item(1);
for (var j = 0; j < parts.length; j++) {
if (parts[j]) cur = cur.Folders.Item(parts[j]);
}
return cur;
};
@ -318,23 +381,54 @@ Outlook.Items = function (items) {
this.get = function (idx) {
var it = this.items.Item(idx);
if (it.Class === Outlook.MailItemClass) {
return new Outlook.MailItem(it);
}
if (!it) return null;
if (it.Class === Outlook.MailItemClass) return new Outlook.MailItem(it);
return new Outlook.Item(it);
};
this.forEach = function (fn, maxCount) {
var n = this.count();
if (typeof maxCount === "number" && maxCount > 0 && maxCount < n) {
n = maxCount;
}
if (typeof maxCount === "number" && maxCount > 0 && maxCount < n) n = maxCount;
for (var i = 1; i <= n; i++) {
fn(this.get(i), i);
}
};
};
Outlook.ItemsFiltered = function (items, predicate) {
// items: Outlook.Items
this.base = (items instanceof Outlook.Items) ? items : new Outlook.Items(items);
this.predicate = predicate;
this.count = function () {
// filtered count is expensive; do not compute
return this.base.count();
};
this.get = function (idx) {
return this.base.get(idx);
};
this.forEach = function (fn, maxCount) {
var n = this.base.count();
var emitted = 0;
for (var i = 1; i <= n; i++) {
var it = this.base.get(i);
if (!it) continue;
if (it instanceof Outlook.MailItem) {
if (this.predicate(it)) {
fn(it, i);
emitted++;
if (typeof maxCount === "number" && maxCount > 0 && emitted >= maxCount) break;
}
}
}
};
};
Outlook.Item = function (item) {
this.item = item;
@ -424,8 +518,99 @@ Outlook.MailItem = function (mail) {
};
};
Outlook.Search = {};
Outlook.Search.filters = {};
Outlook.Search.filters._escape = function (s) {
return (s + "").replace(/'/g, "''");
};
Outlook.Search.filters.subjectContains = function (keyword) {
var k = Outlook.Search.filters._escape(keyword);
return "([Subject] LIKE '%" + k + "%')";
};
Outlook.Search.filters.senderContains = function (keyword) {
var k = Outlook.Search.filters._escape(keyword);
return "([SenderEmailAddress] LIKE '%" + k + "%') OR ([SenderName] LIKE '%" + k + "%')";
};
Outlook.Search.filters.senderEmailEquals = function (email) {
var e = Outlook.Search.filters._escape(email);
return "([SenderEmailAddress] = '" + e + "')";
};
Outlook.Search.filters.recipientContains = function (keyword) {
var k = Outlook.Search.filters._escape(keyword);
return "([To] LIKE '%" + k + "%') OR ([CC] LIKE '%" + k + "%') OR ([BCC] LIKE '%" + k + "%')";
};
Outlook.Search.filters.senderOrToCcBccContains = function (keyword) {
var k = Outlook.Search.filters._escape(keyword);
return "(" +
"([SenderEmailAddress] LIKE '%" + k + "%') OR ([SenderName] LIKE '%" + k + "%')" +
" OR ([To] LIKE '%" + k + "%') OR ([CC] LIKE '%" + k + "%') OR ([BCC] LIKE '%" + k + "%')" +
")";
};
Outlook.Search.filters.receivedSince = function (dateObj) {
// Outlook filter date string is locale-dependent; use Date's default string.
// In WSH/JScript, Date string typically matches system locale and Outlook accepts it.
return "([ReceivedTime] >= '" + dateObj + "')";
};
Outlook.Search.match = {};
Outlook.Search.match._contains = function (hay, needle) {
return (hay + "").toLowerCase().indexOf((needle + "").toLowerCase()) >= 0;
};
Outlook.Search.match.senderOrRecipientObjectContains = function (mailItem, keyword) {
var k = keyword + "";
if (Outlook.Search.match._contains(mailItem.getSenderEmailAddress() || "", k)) return true;
if (Outlook.Search.match._contains(mailItem.getSenderName() || "", k)) return true;
if (Outlook.Search.match._contains(mailItem.mail.To || "", k)) return true;
if (Outlook.Search.match._contains(mailItem.mail.CC || "", k)) return true;
if (Outlook.Search.match._contains(mailItem.mail.BCC || "", k)) return true;
var r = mailItem.mail.Recipients;
for (var i = 1; i <= r.Count; i++) {
var ri = r.Item(i);
if (Outlook.Search.match._contains(ri.Address || "", k)) return true;
if (Outlook.Search.match._contains(ri.Name || "", k)) return true;
}
return false;
};
Outlook.FileExtensions = FileTypes.getExtensionsByOpenWith("msoutlook");
/*
EXAMPLE:
var ol = new Outlook().open().selectFolder(Outlook.Folders.Inbox);
// sender contains
ol.searchBySenderContains("amazon.com").forEach(function(m) {
console.log("[S] " + m.getSenderEmailAddress() + " | " + m.getSubject());
}, 10);
// recipient contains
ol.searchByRecipientContains("me@example.com").forEach(function(m) {
console.log("[R] " + (m.mail.To || "") + " | " + m.getSubject());
}, 10);
// sender OR recipient contains (includes Recipients collection check)
ol.searchBySenderOrRecipientContains("team@company.com").forEach(function(m) {
console.log("[SR] " + m.getSubject());
}, 10);
ol.close();
*/
exports.Excel = Excel;
exports.PowerPoint = PowerPoint;
exports.Word = Word;