-
-
Save astoiccoder/77577ea58eaf2a9b91cee8ca78c0a6f0 to your computer and use it in GitHub Desktop.
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) | |
}); | |
} |
Hi @Ypolites, thanks for reaching out!
Your error message basically says, that the message
object in line 36 is not there, which is probably caused by thread.getMessages()
returning an empty array in line 8.
To verify this you could add this line console.log(JSON.stringify(thread.getMessages(), null, 2));
before line 8 and see what is printed in the output when you run the script again.
If the assumption is correct, it would print something like
11:13:59 AM Info []
To solve this my assumption would be that this is related to the threading feature of gmail. Would be interesting to know if you have the conversation view on or off (https://support.cloudhq.net/how-to-turn-off-threaded-conversations-in-gmail/).
If you could take a small screenshot of how the email looks in your inbox, it could be very helpful to find the issue.
In any case, I am happy to help :)
Hi, thanks so much for this! I use notion and a ReMarkable and this will make my life so much easier!
I am also struggling with an error message that I am not sure how to resolve - please can you help? Thanks :)
6:20:59 PM 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: body.children[0].paragraph.rich_text[0].text.content.le... (use muteHttpExceptions option to examine full response)
postToNotion @ Code.gs:56
(anonymous) @ Code.gs:9
gmailToNotion @ Code.gs:7
Hi, thanks so much for this! I use notion and a ReMarkable and this will make my life so much easier!
I am also struggling with an error message that I am not sure how to resolve - please can you help? Thanks :)
6:20:59 PM 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: body.children[0].paragraph.rich_text[0].text.content.le... (use muteHttpExceptions option to examine full response) postToNotion @ Code.gs:56 (anonymous) @ Code.gs:9 gmailToNotion @ Code.gs:7
Hi @emdsquared, thanks for catching this - I actually always only send rather small converted notes, but I saw from your error message that the limits for the content was reached. You can view them here https://developers.notion.com/reference/request-limits#limits-for-property-values.
I updated this gist to chunk the message body now so that it will also work for larger messages.
In total the script can now handle messages of up to 2000*100 = 200.000 characters or 500kb message size total.
I manually copied the changes over from the working script, so I hope I didn't mess anything up. Let me know if it works when you get to try it :)
Cheers!
Hi @astoiccoder, thanks for responding so quickly! That now works perfectly! :)
Hey @astoiccoder thanks for building this awesome automation!
I ran into a problem I'm afraid.
Exception: Request failed for https://api.notion.com returned code 404. Truncated server response: {"object":"error","status":404,"code":"object_not_found","message":"Could not find database with ID: 4019fcaa-ec18-4622-b464-7411e568e559. Make sur... (use muteHttpExceptions option to examine full response)
I've tried multiple times to make a new database and tried that ID but keeps giving me this error. Would you know what I'm doing wrong?
Hey @astoiccoder thanks for building this awesome automation! I ran into a problem I'm afraid. Exception: Request failed for https://api.notion.com returned code 404. Truncated server response: {"object":"error","status":404,"code":"object_not_found","message":"Could not find database with ID: 4019fcaa-ec18-4622-b464-7411e568e559. Make sur... (use muteHttpExceptions option to examine full response)
I've tried multiple times to make a new database and tried that ID but keeps giving me this error. Would you know what I'm doing wrong?
Whoops sorry... Never mind, I forgot to add the Notion integration in the database in Notion. Now it works perfectly. :)
Whoops sorry... Never mind, I forgot to add the Notion integration in the database in Notion. Now it works perfectly. :)
Hi @Barendgoes, I'm having the same error, but I don't get what you did. I created remarkable integration in connections and defined an empty database (no data source). But I still get the DB not found message. Could you please be more specific?
Hi @diodon You also have to add the integration in the database you've created in Notion. So in Notion go to your created database and click on the 3 dots at the top right corner for settings. In there you'll find Connections, you can find your created Remarkable Integration there and have to select it. So that the Remarkable Integration is actually linked or has access to your database. That did the trick for me, hope this helps for you as well!
Hi @astoiccoder , thanks for pulling this all together. I can't wait to start using this to stay organized. Couple issues arose:
The PDF is being sent to my gmail, but the document does not make it to the notion, only the Subject.
Only 1 page of the PDF gets sent from the remarkable to gmail, is there a way to send multiple pages at once?
Thanks again,
Hi @astoiccoder , thanks for pulling this all together. I can't wait to start using this to stay organized. Couple issues arose:
The PDF is being sent to my gmail, but the document does not make it to the notion, only the Subject. Only 1 page of the PDF gets sent from the remarkable to gmail, is there a way to send multiple pages at once?
Thanks again,
Edit: I was able to send multiple PDFs to gmail from the remarkable, but the content of the PDF is not being relayed to Notion, although the subject line appears.. very strange. Wondering if it is a setting filter or a change can be made to the script.
Hi @astoiccoder , thanks for pulling this all together. I can't wait to start using this to stay organized. Couple issues arose:
The PDF is being sent to my gmail, but the document does not make it to the notion, only the Subject. Only 1 page of the PDF gets sent from the remarkable to gmail, is there a way to send multiple pages at once?
Thanks again,
Hi @crushcup, thanks for reaching out! The remarkable changed the way it converts handwritten notes to text.
Before you always had to send it via email directly, but now conversation creates a new page in the current document containing the converted text. The send by email functionality lets you now choose in the buttom left corner if you want to send your pages as pdf attachments or as "Text in email".
So if you are converting text and want to sent it to your notion, you could choose the "Text in email" option and the script would still work as intended.
The tricky part comes with the pdf attachments (e.g. if you also want to send handwritten notes which would not be included with the "Text in email" option).
Notion unfortunately does not allow a file upload via API.
So I thought I could still make the pdfs show up on the page by storing the files to google drive with the script and then show them as an embed block on the notion page with the google drive integration, but adding a link_preview to a notion page is also not possible via API. Even in mention blocks it is not possible to add a link_preview.
The only thing I could find is now to copy the file to a google drive folder and then add the link to that google drive file to the notion page. But then of course it won't show a nice preview. If you want to have that, all you need to do is create a new google drive folder and copy the folder id from the url when you are inside the folder over to the latest version of the script.
Wish you a great weekend!
Hey @astoiccoder thank you so much for building this!
Everything looks good on my end but it is not showing up in notion
Hey @astoiccoder thank you so much for building this!
Everything looks good on my end but it is not showing up in notion
Hi @doggiecuddles,
A few things important to check could be:
- Did you use the "Text in email" option when sending the note from the remarkable?
- Are both labels ('NotionToSync' and 'SyncedToNotion') applied correctly on the emails that are being sent? That's a first indicator if the script is actually running through.
- Do you see any errors in the google apps script? (If the request to create the page in notion fails, it should show an error in the script - in order to check that you can also manually run the script after sending a fresh email or removing the 'SyncedToNotion' label on any prior email and run the script again)
hello! i'm struggling with this right now,
Exception: Request failed for https://api.notion.com returned code 401. Truncated server response: {"object":"error","status":401,"code":"unauthorized","message":"API token is invalid.","request_id":
getting the above response. nothing shows up in the database. i use convert to text and when emailing "text to email"
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)
Hi there !
Terrific idea. I tried it on my side (as your tutorial was very clear) unfortunaly I keep running in the error:
I'm affraid I'm note enought of a programmer myself to solve this.
If you are disposed to help me it would be grand !
Cheers !