The reMarkable e-ink tablet is primarily meant to serve as a replacement for paper notebooks. It makes for a great PDF reader with things like technical manuals or scientific papers. While the tablet offers an outstanding screen and writing experience, the software is somewhat lacking. This post will summarize a setup I implemented to transfer PDF files to my reMarkable by emailing them to myself.
Existing transfer options
The easiest way to transfer files to the reMarkable is by using the desktop application. However, it is not currently officially available for Linux. There is also a mobile app for file transfer, but that then involves the extra step of sending the file I want to my phone. There’s also the option of transfer via USB, which uses a simple Web server built into the reMarkable. This is a good method but of course requires the USB cable to be connected.
Transfer over email
A transfer option that I would like is to just email a file to a certain address, and have it show up on my reMarkable. Amazon Kindle has this feature and it is very convenient. There is nothing like that for the reMarkable, but it turns out to be quite easy to implement relying on some existing software.
My setup consists of the following:
reMarkable tablet, with cloud services enabled.
A Postfix email server.
A simple Python script to process emails sent to an email address I allocate for the reMarkable.
On the server, you need to install rmapi first, by following the instructions on Github. In my case, with golang already installed, it was sufficient to run
go get -u github.com/juruen/rmapi.
The server’s rmapi installation needs to be connected to the cloud, so you have to run rmapi once and input the one-time code from my.remarkable.com. This is a one-time operation.
After that, you need to create an email address for the reMarkable tablet, and have it forward to a script. Configuration details depend on the server. I chose
remarkable -at- umanovskis (dot) se as the address, so the Postfix configuration looks like this:
First, a new virtual entry in
/etc/postfix/virtual (email written properly using the @ sign):
remarkable -at- umanovskis.se remarkable-alias
remarkable-alias in turn forwards to a script. This is because virtualdb entries cannot directly forward to a script, so the two steps are needed. To make it cleaner, I don’t add the alias globally but put it in my
~/.aliases, as follows
remarkable-alias: "|/home/duman/remarkable-mail.py --authorized-senders-only"
Done like this, the user-specific aliases file has to be included in
alias_maps of Postfix
main.cf as well. After running
postmap && newaliases and reloading Postfix, there’s a new email address that forwards to a Python script.
With the server configured, the remainder of the task is to have the Python script that will receive emails, check for pdf attachments and upload them via rmapi. I am not very strong at Python so the resulting code is not particulary “Pythonic”, but serves the purpose well for a late-night hack.
#!/usr/bin/python import sys, subprocess from os.path import expanduser from datetime import datetime import email import email.utils class RemarkableMailer: def __init__(self): self.loglines =  self.homedir = expanduser("~") self.logfile = self.homedir + "/remarkable/mailer.log" self.authorized_senders =  self.validate_senders = False self.input = "" self.rmapi = self.homedir + "/go/bin/rmapi" def log(self, message): timestamp = datetime.now().strftime('[%d-%m-%Y %H:%M] ') self.loglines.append(timestamp + message + "\n") def write_log(self): try: with open(self.logfile, 'a') as f: f.writelines(self.loglines) except Exception as e: print e def load_authorized_senders(self): try: with open(self.homedir + "/.authorized_script_senders", "r") as scripts_file: authorized_senders = [l.rstrip() for l in scripts_file.readlines() if not l.startswith('#')] except IOError as e: self.log(e) def run(self, argv): if "--authorized-senders-only" in argv: self.log("Running with whitelist") self.load_authorized_senders() self.validate_senders = True self.input = sys.stdin.read() if len(self.input) > 0: email, sender = self.process_input() if email is not None: valid_sender = self.validate_senders and sender in self.auhtorized_senders if valid_sender or self.validate_senders == False: self.log ("Processing email from " + sender) filelist = self.extract_pdfs(email) self.upload(filelist) else: self.log ("Ignoring unauthorized sender " + sender) def save_raw(self, data): try: raw = open(self.homedir + "/remarkable/raw-email", "w") raw.write(data) raw.close() except Exception: pass def process_input(self): try: # Enable for debug #self.save_raw(self.input) msg = email.message_from_string(self.input) sender = msg.get_all('from') return (msg, email.utils.parseaddr(sender)) except Exception as e: self.log(str(e)) return (None, None) def extract_pdfs(self, email): saved_files =  if email.is_multipart(): for part in email.get_payload(): if part.get_content_type() == "application/pdf": payload = part.get_payload(decode=True) filename = part.get_filename() self.save_pdf(filename, payload) saved_files.append(filename) return saved_files def save_pdf(self, filename, contents): with open(self.homedir + "/remarkable/" + filename, "w") as f: try: f.write(contents) self.log ("Saved " + filename) except Exception as e: self.log ("Failed writing " + filename) def upload(self, files): for f in files: path = self.homedir + "/remarkable/" + f self.log("Uploading " + path + " to tablet") proc = subprocess.call([self.rmapi, "put", path], shell=False, timeout=20) subprocess.call(["rm", path]) if __name__ == "__main__": mailer = RemarkableMailer() mailer.run(sys.argv) mailer.write_log()
The script attempts to parse standard input as an email and, in the case of success, looks for PDF attachments (identifying them by the
application/pdf MIME type), temporarily saves them to the file system and calls rmapi to upload to the reMarkable cloud. I also verify that the email’s sender is in a whitelist, which is a neat detail I like for scripts that can be triggered by email. It’s not a serious security solution, but prevents script activation by spambots that could scrape the email from somewhere.
As a result, this setup allows me to simply email a PDF file, and have it show up on the reMarkable as soon as the tablet has a Wifi connection available.comments powered by Disqus