Hi fellow self-hosting lemmings,
In an SME setting, I’m looking for a service to regularly fetch mails from an IMAP server and print incoming mails and attachments on a local network printer based on rules (e.g., only print mails where the subject contains a specific word.)
Does a solution like that exist, ideally with a browser frontend to set it up?
Thank you!
https://github.com/nickrussler/email-to-pdf-converter
Make a script using your email clients files and pack it in a cronjob/scheduled task.
Thanks for the reply. I don’t think I fully understand what you mean.
What I would like to have is a service running on a server, fetching and printing mails. Could you please elaborate how your idea would work?
… forget it. I was about to write a long-winded answer, that you can use usual cli mail softare to fetch the eml or msg files (mails) and use the tool on them and then send the pdf to the printers (most printers use pdf internally). But then i remembered that this would be the perfect job for a python script.
But, uh, wouldn’t you better just save the mails instead of printing them? Environment and cost and so on.
Gotcha. Thanks anyway. 🙂
You’re right about printing not being all that, but certain situations (my situation) call for it, at least for the time being.
This is for manufacturing orders in a low tech environment, and at this point in time I need to stick with a paper trail (so I can get rid of it in the future.)
Now this is an idea I like. Thank you so much, I never would have considered Node-RED for this application!
I actually use NR to keep an eye on my CUPS print queue for jobs waiting, and it sends a wakeup to a tasmota wall plug to turn on the printer and then turn it off in 5 minutes. This lets me have a network printer always ready, but not using power in idle. This might work in with your project.
spoiler
[{“id”:“6f4056a8.eb32”,“type”:“inject”,“z”:“f268801.6c137”,“name”:“”,“props”:[{“p”:“payload”},{“p”:“topic”,“vt”:“str”}],“repeat”:“60”,“crontab”:“”,“once”:false,“onceDelay”:0.1,“topic”:“”,“payload”:“”,“payloadType”:“date”,“x”:250,“y”:240,“wires”:[[“5e57130e.32c56c”]]},{“id”:“5a7d9cb9.82e2ac”,“type”:“html”,“z”:“f268801.6c137”,“name”:“”,“property”:“payload”,“outproperty”:“payload”,“tag”:“.list > tbody:nth-child(2) > tr:nth-child(1) > td:nth-child(1) > a:nth-child(1)”,“ret”:“html”,“as”:“single”,“x”:370,“y”:300,“wires”:[[“667f6421.e13924”]]},{“id”:“5e57130e.32c56c”,“type”:“http request”,“z”:“f268801.6c137”,“name”:“”,“method”:“GET”,“ret”:“txt”,“paytoqs”:“ignore”,“url”:“http://10.10.251.50:631/jobs?“,“tls”:”“,“persist”:false,“proxy”:”“,“authType”:”“,“x”:420,“y”:240,“wires”:[[“5a7d9cb9.82e2ac”]]},{“id”:“667f6421.e13924”,“type”:“split”,“z”:“f268801.6c137”,“name”:”“,“splt”:”\\n",“spltType”:“str”,“arraySplt”:1,“arraySpltType”:“len”,“stream”:false,“addname”:“”,“x”:180,“y”:380,“wires”:[[“836d047d.c5a41”]]},{“id”:“836d047d.c5a41”,“type”:“switch”,“z”:“f268801.6c137”,“name”:“”,“property”:“payload”,“propertyType”:“msg”,“rules”:[{“t”:“eq”,“v”:“HP_LaserJet_4000_Series”,“vt”:“str”},{“t”:“null”}],“checkall”:“true”,“repair”:false,“outputs”:2,“x”:330,“y”:380,“wires”:[[“474b85e1.a317ec”],[]]},{“id”:“be8ec1f.57fad4”,“type”:"Tasmota Switch”,“z”:“f268801.6c137”,“broker”:“4ba22e0f7edb8148”,“device”:“tasmota_LJ4000”,“name”:“”,“outputs”:1,“uidisabler”:false,“fullTopic”:“”,“cmndPrefix”:“”,“statPrefix”:“”,“telePrefix”:“”,“x”:700,“y”:380,“wires”:[[]]},{“id”:“474b85e1.a317ec”,“type”:“trigger”,“z”:“f268801.6c137”,“name”:“”,“op1”:“1”,“op2”:“0”,“op1type”:“str”,“op2type”:“str”,“duration”:“5”,“extend”:true,“overrideDelay”:false,“units”:“min”,“reset”:“”,“bytopic”:“all”,“topic”:“topic”,“outputs”:1,“x”:510,“y”:380,“wires”:[[“be8ec1f.57fad4”]]},{“id”:“316b902c.639208”,“type”:“comment”,“z”:“f268801.6c137”,“name”:“LaserJet 4k Wakeup on Print”,“info”:“”,“x”:140,“y”:200,“wires”:[]},{“id”:“4ba22e0f7edb8148”,“type”:“tasmota-mqtt-broker”,“name”:“”,“broker”:“localhost”,“port”:“1883”,“clientid”:“”,“usetls”:false,“keepalive”:“60”,“cleansession”:true}]
I do actually use Node-RED myself for my zigbee home automation. Funny how it never crossed my mind to pick it up for this. It’s perfect as I want a non-programmer to be able to maintain it.
I doubt my solution will be much more than ingest and print, but I’ll report back. Still fighting to get that hp p3015 to do something over IPP…
BTW, if you do end up using this method, I’d love to see your implementation some day. Node Red is so useful and intuitive IMO, and people sharing their solutions is valuable.
One deep dive into the IPP protocol, printer drivers, and specific supported formats (“what the hell is an octet-stream?!”) later, I have something functional.
I’m not a JS guy, so I don’t know if it’s a very node-y way to do it. But except for the pages coming out a little scaled this works:
Edit to briefly explain what this does: The mail node ingests unread emails and passes them forward to a function node that checks for pdf attachments. Those are passed forward one by one to a function node that takes care of converting the pdf to pcl (my printer supposedly knows how to handle pdf 1.7 but doesn’t, so I had to resort to this) and passes it to the IPP node as a data buffer .
spoiler
[ { "id": "86082bed0ed29155", "type": "IPPrint", "z": "08cc7c15668f2f65", "name": "Print to Network", "IP": "10.10.0.19:631/ipp/print", "JOB_name": "default_job_name", "authuser": "", "authpassword": "", "authcheck": "", "x": 780, "y": 120, "wires": [ [ "b1a8b92ede8a78a5" ] ] }, { "id": "b1a8b92ede8a78a5", "type": "debug", "z": "08cc7c15668f2f65", "name": "debug 1", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 960, "y": 120, "wires": [] }, { "id": "1fb7fc3843af8e05", "type": "function", "z": "08cc7c15668f2f65", "name": "Convert PDF to PCL", "func": "const baseOptions = {\n width: 2480,\n height: 3508,\n density: 300,\n preserveAspectRatio: true,\n format: 'PCL'\n};\n\n// prepare conversion function\nconst convert = await pdf2pic.fromBuffer(msg.payload, baseOptions);\n// set additional conversion options\nconvert.setGM\n// bulk convert the whole input buffer to a pcl output buffer\nconvert.bulk(-1, {responseType: \"buffer\"}).then((outputs)=>{\n // pass each page on to the printer\n outputs.forEach((output, index) => {\n msg.payload = output.buffer;\n if(msg.topic){\n let jobname = msg.topic\n }\n msg.JOBName = (msg.topic ? msg.topic : \"Mailjob\").concat(\" \", index+1, \"/\", outputs.length);\n msg.docFormat = \"application/octet-stream\";\n node.send(msg);\n });\n});\n", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [ { "var": "pdf2pic", "module": "pdf2pic" } ], "x": 560, "y": 120, "wires": [ [ "86082bed0ed29155" ] ] }, { "id": "224317e794da3cb5", "type": "e-mail in", "z": "08cc7c15668f2f65", "name": "Mail ingest", "protocol": "IMAP", "server": "test.mail.com", "useSSL": false, "autotls": "always", "port": "143", "authtype": "BASIC", "saslformat": true, "token": "oauth2Response.access_token", "box": "INBOX", "disposition": "Read", "criteria": "UNSEEN", "repeat": "300", "fetch": "auto", "inputs": 0, "x": 160, "y": 80, "wires": [ [ "2fedaa18c9394b89" ] ] }, { "id": "2fedaa18c9394b89", "type": "function", "z": "08cc7c15668f2f65", "name": "PDF Filter", "func": "if(msg.attachments.length > 0){\n msg.attachments.forEach(function(attachment) {\n if(attachment.contentType == \"application/pdf\"){\n var newmsg = {};\n newmsg.topic = msg.topic;\n newmsg.filename = attachment.filename;\n newmsg.payload = attachment.content;\n node.send(newmsg);\n }\n });\n}", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 360, "y": 80, "wires": [ [ "1fb7fc3843af8e05" ] ] }, { "id": "3d8f7ad8e6b56d46", "type": "inject", "z": "08cc7c15668f2f65", "name": "Test print", "props": [ { "p": "payload" }, { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 160, "y": 160, "wires": [ [ "683ed6fe7c10540d" ] ] }, { "id": "683ed6fe7c10540d", "type": "file in", "z": "08cc7c15668f2f65", "name": "", "filename": "/data/2517.pdf", "filenameType": "str", "format": "", "chunk": false, "sendError": false, "encoding": "none", "allProps": false, "x": 340, "y": 160, "wires": [ [ "1fb7fc3843af8e05" ] ] } ]
Nicely done, for not a JS guy. I’d have be a while longer figuring out that process.
Not sure what to suggest on the scaling, that might be happening in your conversion to PCL, you might be able to execute that as a ghostscript process on the host and then just stream the resulting file out of the filesystem to the print node, or even just drop it to a queue folder and cut the IPP node out entirely to eliminate it as a source of the scaling.
A very welcome compliment after this ordeal. Thank you! :)
The cleanest way to solve the scaling issue would probably be to go into the pdf2pic module and hack it open to accept the “pcl:fit-to-page” option that GraphicsMagick (the underlying software package doing the actual conversion from PDF to PCL) supports. (Supposing it actually does what it says. I’m not so sure about anything in printer land anymore.)
But since this whole thing is for internal documents only and the scaling can probably be estimated by choosing better values for width/height to account for printer margins I most likely won’t bother.
Thanks again for suggesting Node-RED. I’m very happy with the result.
There’s an outlook addon that does exactly this, it’s not free but works as advertised
Thank you for the suggestion. Not exactly what I’m looking for, sadly.
You might want to check out Mozilla Thunderbird or even MS outlook for this. I don’t believe roundcube (web client) has this ability.
Thanks for the idea. It’s not quite what I was looking for, but I might look into it more if I don’t find anything better.
From the looks of it, it requires python scripting anyway, so there isn’t a big advantage to fetching the mail with python and imaplib directly.