Last active
July 2, 2024 15:08
-
-
Save astoiccoder/77577ea58eaf2a9b91cee8ca78c0a6f0 to your computer and use it in GitHub Desktop.
reMarkable to Notion Sync
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const GMAIL_LABEL_NAME = 'NotionToSync'; | |
const SYNCED_LABEL = 'SyncedToNotion'; | |
// if you set this, the attachments will be copied over to google drive and the links added to the notion page | |
const GDRIVE_FOLDER_ID = ''; | |
const gmailToNotion = () => { | |
const label = GmailApp.getUserLabelByName(GMAIL_LABEL_NAME); | |
const successLabel = GmailApp.getUserLabelByName(SYNCED_LABEL); | |
label.getThreads(0, 20).forEach((thread) => { | |
const [message] = thread.getMessages().reverse(); | |
postToNotion(message); | |
thread.removeLabel(label); | |
thread.addLabel(successLabel) | |
}); | |
}; | |
function getRichTextChunks(messageBody) { | |
let remainingString = messageBody; | |
const content = []; | |
while (remainingString.length > 0) { | |
// https://developers.notion.com/reference/request-limits#limits-for-property-values | |
if (remainingString.length <= 2000) { | |
content.push(getRichTextObjectForChunk(remainingString)); | |
remainingString = ''; | |
} else { | |
const maximalChunk = remainingString.substring(0, 2000); | |
const lastLineBreakInChunk = maximalChunk.lastIndexOf('\n'); | |
const actualChunk = remainingString.substring(0, lastLineBreakInChunk); | |
content.push(getRichTextObjectForChunk(actualChunk)); | |
remainingString = remainingString.substring(lastLineBreakInChunk + 1); | |
} | |
} | |
return content; | |
} | |
function getRichTextObjectForChunk(messageChunk) { | |
return { | |
type: 'text', | |
text: { | |
content: messageChunk | |
}, | |
} | |
} | |
function getPdfBlocksForAttachments(message) { | |
var attachments = message.getAttachments(); | |
var pdfBlocks = []; | |
for (var k = 0; k < attachments.length; k++) { | |
Logger.log('Message contains the attachment "%s" (%s bytes)', attachments[k].getName(), attachments[k].getSize()); | |
var folder = DriveApp.getFolderById(GDRIVE_FOLDER_ID); | |
var ts = Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "yyMMddHHmmss"); | |
var createdFile = folder.createFile(attachments[k].copyBlob()).setName(attachments[k].getName() + ts); | |
pdfBlocks.push({ | |
"object": "block", | |
"type": "paragraph", | |
"paragraph": { | |
"rich_text": [ | |
{ | |
"type": "text", | |
"text": { | |
"content": attachments[k].getName(), | |
"link": { | |
"url": createdFile.getUrl() | |
} | |
}, | |
"annotations": { | |
"bold": false, | |
"italic": false, | |
"strikethrough": false, | |
"underline": false, | |
"code": false, | |
"color": "default" | |
}, | |
"plain_text": attachments[k].getName(), | |
"href": createdFile.getUrl() | |
} | |
], | |
"color": "default" | |
} | |
}) | |
} | |
} | |
function postToNotion(message) { | |
const richTextChunks = getRichTextChunks(message.getPlainBody()); | |
const pdfBlocks = GDRIVE_FOLDER_ID ? getPdfBlocksForAttachments(message) : []; | |
const url = 'https://api.notion.com/v1/pages'; | |
const body = { | |
parent: { | |
type: "database_id", | |
database_id: "<Your Target Notion Database Id>", | |
}, | |
icon: { | |
type: "emoji", | |
emoji: "📝" | |
}, | |
children: [ | |
...pdfBlocks, | |
{ | |
object: 'block', | |
type: 'paragraph', | |
paragraph: { | |
rich_text: richTextChunks, | |
}, | |
} | |
], | |
properties: { | |
Name: { | |
title: [ | |
{ | |
text: { | |
content: message.getSubject(), | |
}, | |
}, | |
], | |
} | |
} | |
} | |
UrlFetchApp.fetch(url, { | |
method: 'post', | |
contentType: "application/json", | |
muteHttpExceptions: false, | |
headers: { | |
Authorization: `Bearer <Your Notion Secret>`, | |
'Notion-Version': '2022-02-22' | |
}, | |
payload: JSON.stringify(body) | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks for doing this @astoiccoder! I love notion and recently gotten my hands on Remarkable. Two truly amazing tools which will be even better if integrated OOTB.
Thanks for building this integration!
Using the latest code, I face a slightly different error.
"Exception: Request failed for https://api.notion.com returned code 400. Truncated server response: {"object":"error","status":400,"code":"validation_error","message":"body failed validation. Fix one:\nbody.parent.page_id should be defined, instea... (use muteHttpExceptions option to examine full response)"
Upon looking into this link "ramnes/notion-sdk-py#72", it seems like property values of the new page in the properties parameter must conform to the parent database's property schema. Any suggestion how to do this?
Thanks in advanced!
Exception: Request failed for https://api.notion.com/ returned code 400. Truncated server response: {"object":"error","status":400,"code":"validation_error","message":"body failed validation. Fix one:\nbody.parent.page_id should be defined, instea... (use muteHttpExceptions option to examine full response)