Skip to content

Instantly share code, notes, and snippets.

@hungerburg
Last active December 20, 2021 02:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save hungerburg/00d582bf1a6bf3c622797bf5e759f75b to your computer and use it in GitHub Desktop.
Save hungerburg/00d582bf1a6bf3c622797bf5e759f75b to your computer and use it in GitHub Desktop.
Quick'n'Dirty Intranet Mail Search with Dovecot and SOLR
<!DOCTYPE html>
<!--
# Quick'n'Dirty Intranet Mail Search
1) Have dovecot index mails in SOLR
2) Configure the doveadm HTTP API
3) Create proxies for SOLR and DOVEADM
4) Search and find!
# /etc/dovecot/local.conf
doveadm_allowed_commands = fetch
doveadm_api_key = secret
service doveadm {
inet_listener http {
port = 8084
address = 127.0.0.1
}
}
# secret64 = echo -n secret | base64
# /etc/apache/.../*trusted-net*site.conf
ProxyVia Block
<Location /doveadm/v1>
RequestHeader set Authorization "X-Dovecot-API secret64"
ProxyPass http://localhost:8084/doveadm/v1 retry=0 timeout=15
ProxyPassReverse http://localhost:8084/doveadm/v1
</Location>
<Location /solr/select>
ProxyPass http://localhost:8983/solr/select retry=0 timeout=5
ProxyPassReverse http://localhost:8983/solr/select
</Location>
-->
<html>
<head>
<meta charset="UTF-8">
<title>SOLR Search Mail Archive</title>
<meta name="viewport" content="width=device-width, user-scalable=no">
<style>
body { font-family: sans-serif; margin: 3ex 3em; }
div { margin-top: 2ex; padding: 2ex 0; border-top: 1px solid silver; }
em { color: darkred; }
#query { width: 100%; }
#result { }
</style>
</head>
<body>
<p><input type="text" id="query" placeholder="Type then Enter"></p>
<p id="result">…</p>
<script>
var start = 0;
var rows = 10;
var user = "archiv";
function pp(str) {
return str
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
}
function fetchlistener() {
var msg = this.response[0][1][0];
var result = document.getElementById("result");
result.innerHTML += "<div>" + pp(msg.mailbox)
+ ": <b>" + pp(msg["hdr.subject.utf8"]) + "</b>"
+ "<br>From: " + pp(msg["hdr.from.utf8"])
+ ", To: " + pp(msg["hdr.to.utf8"])
+ "<br>Date: " + pp(msg["date.sent"])
+ ", Size: " + pp(msg["size.physical"])
+ "<br><br><em>" + pp(msg["body.snippet"])
+ "</em></div>";
}
function fetch(doc) {
var req = new XMLHttpRequest();
req.responseType = "json";
req.addEventListener("load", fetchlistener);
var url = "/doveadm/v1";
req.open("POST", url);
req.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
req.send(JSON.stringify(
[[ "fetch", {
"user": user,
"field": [ "mailbox", "date.sent", "hdr.from.utf8", "hdr.to.utf8", "hdr.subject.utf8", "size.physical", "body.snippet" ],
"query": [ "mailbox-guid", ""+doc.box, "uid", ""+doc.uid ]
}, "cid"
]]
));
}
function searchlistener() {
var resp = this.response.response;
var docs = resp.docs;
result.innerHTML = "Listing - Please wait… "
+ "Start: " + resp.start
+ ", Rows : " + docs.length
+ ", Found: " + resp.numFound;
for (doc in docs) {
fetch(docs[doc]);
}
}
function search(str) {
var req = new XMLHttpRequest();
req.responseType = "json";
req.addEventListener("load", searchlistener);
str = str.replace(/[^\wäöüß]/gi, " ").trim();
var url = "/solr/select"
+'?q=body:'+ str.replace(/[ ]{1,}/g, " body:")
+' user:'+user
+'&start='+start
+'&rows='+rows
+'&fl=box,uid&wt=json';
req.open("GET", url);
req.send();
var result = document.getElementById("result");
result.innerHTML = "Searching - Please wait…";
}
var query = document.getElementById("query");
query.addEventListener('keypress', function (e) {
if (e.key === 'Enter') { search(this.value); }
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment