Skip to content

Instantly share code, notes, and snippets.

@Rican7
Last active October 20, 2020 06:31
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Rican7/867cb9dee1555528041865bc3b8cdd11 to your computer and use it in GitHub Desktop.
Save Rican7/867cb9dee1555528041865bc3b8cdd11 to your computer and use it in GitHub Desktop.
Filters Gmail message threads to apply helpful GitHub labels, for organization.
/**
* Labels Gmail email threads
*/
function labelGithubEmails() {
/**
* Gmail label names for GitHub messages
*/
const githubLabelName = 'GitHub'
const githubPullRequestLabelName = 'GitHub/Pull Request'
const githubIssueLabelName = 'GitHub/Issue'
const githubDiscussionLabelName = 'GitHub/Discussion'
const githubReleaseLabelName = 'GitHub/Release'
const githubCommitLabelName = 'GitHub/Commit'
const githubLabel = GmailApp.getUserLabelByName(githubLabelName)
const githubPullRequestLabel = GmailApp.getUserLabelByName(githubPullRequestLabelName)
const githubIssueLabel = GmailApp.getUserLabelByName(githubIssueLabelName)
const githubDiscussionLabel = GmailApp.getUserLabelByName(githubDiscussionLabelName)
const githubReleaseLabel = GmailApp.getUserLabelByName(githubReleaseLabelName)
const githubCommitLabel = GmailApp.getUserLabelByName(githubCommitLabelName)
/**
* The query to use when finding messages to process
*
* Tweak this to improve the processing time/performance of messages, especially to prevent reaching maximum time/limits defined in the quotas.
*
* See: https://support.google.com/mail/answer/7190
* See: https://developers.google.com/apps-script/guides/services/quotas#current_limitations
*/
const gmailSearchQuery = '(label:github AND NOT label:github-pull-request AND NOT label:github-issue AND NOT label:github-discussion AND NOT label:github-release AND NOT label:github-commit) AND newer_than:1d';
const rfc822MessageIdHeaderName = 'Message-ID'
const pullRequestMessageIdRegex = /.*\/pull(s)?\/.*@github.com/i;
const issueMessageIdRegex = /.*\/issue(s)?\/.*@github.com/i;
const discussionMessageIdRegex = /.*\/discussion(s)?\/.*@github.com/i;
const releaseMessageIdRegex = /.*\/release(s)?\/.*@github.com/i;
const commitMessageIdRegex = /.*\/commit(s)?\/.*@github.com/i;
const maxPerPage = 50;
var startIndex = 0;
do {
var threads = GmailApp.search(gmailSearchQuery, startIndex, maxPerPage);
Logger.log('Gmail search query found %s results, with a range of %s-%s', threads.length, startIndex, (startIndex + maxPerPage))
threads.forEach(function (gmailThread) {
var firstMessage = gmailThread.getMessages()[0];
var mailRFCMessageIds = getEmailHeaderValues(firstMessage.getRawContent(), rfc822MessageIdHeaderName);
// Determine the type of message
var [isPullRequest, isIssue, isDiscussion, isRelease, isCommit] = mailRFCMessageIds.reduce(
function ([isPullRequestMessage, isIssueMessage, isDiscussionMessage, isReleaseMessage, isCommitMessage], messageId) {
// Test for message type
isPullRequestMessage = isPullRequestMessage || pullRequestMessageIdRegex.test(messageId);
isIssueMessage = isIssueMessage || issueMessageIdRegex.test(messageId);
isDiscussionMessage = isDiscussionMessage || discussionMessageIdRegex.test(messageId);
isReleaseMessage = isReleaseMessage || releaseMessageIdRegex.test(messageId);
isCommitMessage = isCommitMessage || commitMessageIdRegex.test(messageId);
return [isPullRequestMessage, isIssueMessage, isDiscussionMessage, isReleaseMessage, isCommitMessage];
},
[false, false, false, false, false]
);
Logger.log('Message (%s) with `Message-ID: %s` detected as %s', firstMessage.getId(), mailRFCMessageIds.join(', '), {"isPullRequest": isPullRequest, "isIssue": isIssue, "isDiscussion": isDiscussion, "isRelease": isRelease, "isCommit": isCommit})
if (isPullRequest) {
gmailThread.addLabel(githubPullRequestLabel);
}
if (isIssue) {
gmailThread.addLabel(githubIssueLabel);
}
if (isDiscussion) {
gmailThread.addLabel(githubDiscussionLabel);
}
if (isRelease) {
gmailThread.addLabel(githubReleaseLabel);
}
if (isCommit) {
gmailThread.addLabel(githubCommitLabel);
}
});
startIndex += threads.length;
} while (threads.length >= maxPerPage);
}
/**
* Gets values for an email header
*/
function getEmailHeaderValues(rawEmail, headerName) {
const headerRegex = new RegExp('^' + headerName + ': (.*(?:\\r?\\n\\s+.*)?)$', 'gim');
var values = [];
do {
var matches = headerRegex.exec(rawEmail);
if (Array.isArray(matches) && 1 in matches) {
values.push(matches[1]);
}
} while (null !== matches);
return values;
}
@Rican7
Copy link
Author

Rican7 commented Jun 30, 2017

To use this filter

  1. Create labels in Gmail that match the names of the labels used in the script. In this script, there's a "GitHub" label, and then there are 4 sub-labels (nested labels) under the "GitHub" label. When done, your label structure in Gmail should look like this:
    screen shot 2017-06-30 at 5 34 41 pm
  2. Open Google Drive and create a new "Google Apps Script"
    screen shot 2017-06-30 at 5 14 16 pm redacted
  3. Paste the code in this gist in a file called main.gs in the Google Apps Script project.
    screen shot 2017-06-30 at 5 23 06 pm
  4. Once pasted, save the project.
  5. Under the Edit menu, choose "Current project's triggers".
    screen shot 2017-06-30 at 5 23 20 pm
  6. Add a "Time-driven" trigger that run's the labelGithubEmails function every minute.
    screen shot 2017-06-30 at 5 23 30 pm

It should work now!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment