-
-
Save sebastienvercammen/e7e0e9e57db246d7f941b789d8508186 to your computer and use it in GitHub Desktop.
| /* | |
| Automatically click all "Verify your email" links in the welcome e-mail from | |
| Nintendo Pokémon Trainer Club's signup e-mails. | |
| Only unread emails in inbox will be processed. | |
| All processed e-mails will be marked as read if verification was successful, | |
| and optionally moved to trash if it's enabled in your settings. | |
| How to use: | |
| 1. Login to Gmail | |
| 2. Go to https://script.google.com/ | |
| 3. Enter the code in Code.gs and index.html (if index.html doesn't exist, create it). | |
| 4. Edit the settings at the top of index.html. | |
| 5. In the editor, click on Resources > Advanced Google services and name your project. | |
| 6. Enable "These services must also be enabled in the Google Developers Console". | |
| 7. Enable GMail API for your new project in the Google Developers Console: https://console.developers.google.com/. | |
| 8. Click Publish, then run as web app. | |
| 9. You'll see the results on the page. Dev console can be used for debugging. | |
| 10. Enjoy | |
| */ | |
| // Serve HTML file. | |
| function doGet() { | |
| return HtmlService.createHtmlOutputFromFile('index.html'); | |
| } | |
| function getAllEmailLinks(limit) { | |
| // Prepare response. | |
| var items = []; | |
| // Start. | |
| var threads = GmailApp.search('in:inbox -label:RM_EXPIRED -label:RM_PREACTIVATED is:unread subject:"Pokémon Trainer Club Activation"', 0, limit); | |
| Logger.log("Found " + threads.length + " threads."); | |
| threads.forEach(function (thread) { | |
| var messages = thread.getMessages(); | |
| Logger.log("Found " + messages.length + " messages."); | |
| messages.forEach(function (msg) { | |
| // If we have a limit, follow it. | |
| if (limit > 0 && items.length >= limit) { | |
| return; | |
| } | |
| var value = msg.getBody() | |
| .match(/verify your email/m); | |
| if (msg.isInInbox() && value) { | |
| var messageId = msg.getId(); | |
| var link = msg.getBody().match(/<a href="https:\/\/club.pokemon.com\/us\/pokemon-trainer-club\/activated\/([\w\d]+)"/); | |
| if (link) { | |
| var url = 'https://club.pokemon.com/us/pokemon-trainer-club/activated/' + link[1]; | |
| // Add to list for front-end. | |
| items.push({ | |
| 'url': url, | |
| 'id': messageId | |
| }); | |
| } | |
| } | |
| }); | |
| }); | |
| Logger.log("Sent " + items.length + " URLs to front-end for verification."); | |
| return items; | |
| } | |
| function labelAsError(messageId, labelName) { | |
| try { | |
| modifyMessage('me', messageId, [ labelName ]); | |
| return { | |
| 'success': true | |
| }; | |
| } catch (e) { | |
| Logger.log(e); | |
| return { | |
| 'success': false, | |
| 'error': e | |
| }; | |
| } | |
| } | |
| function markAsVerified(messageId, move_to_trash) { | |
| var msg = GmailApp.getMessageById(messageId); | |
| msg.markRead(); | |
| if (move_to_trash) { | |
| msg.moveToTrash(); | |
| } | |
| } | |
| /* | |
| * Below methods are Google Apps Script Gmail Utilities, by mogsdad: | |
| * https://gist.github.com/mogsdad/6515581 | |
| */ | |
| /** | |
| * Modify the Labels a Message is associated with. | |
| * Throws if unsuccessful. | |
| * see https://developers.google.com/gmail/api/v1/reference/users/messages/modify | |
| * | |
| * @param {String} userId User's email address. The special value 'me' | |
| * can be used to indicate the authenticated user. | |
| * @param {String} messageId ID of Message to modify. | |
| * @param {String} labelsToAdd Array of Label names to add. | |
| * @param {String} labelsToRemove Array of Label names to remove. | |
| * | |
| * @returns {Object} Users.messages resource, see reference. | |
| */ | |
| function modifyMessage(userId, messageId, labelsToAdd, labelsToRemove) { | |
| labelsToAdd = labelsToAdd || []; | |
| labelsToRemove = labelsToRemove || []; | |
| // see https://developers.google.com/gmail/api/v1/reference/users/messages/modify | |
| var url = 'https://www.googleapis.com/gmail/v1/users/${userId}/messages/${id}/modify' | |
| .replace("${userId}", "me") | |
| .replace("${id}", messageId); | |
| var headers = { | |
| Authorization: 'Bearer ' + ScriptApp.getOAuthToken() | |
| }; | |
| var addLabelIds = []; | |
| for (var i = 0; i < labelsToAdd.length; i++) { | |
| addLabelIds[i] = getLabelId(labelsToAdd[i]); | |
| } | |
| var removeLabelIds = []; | |
| for (var i = 0; i < labelsToRemove.length; i++) { | |
| removeLabelIds[i] = getLabelId(labelsToRemove[i], false); | |
| } | |
| var request = { | |
| 'addLabelIds': addLabelIds, | |
| 'removeLabelIds': removeLabelIds | |
| }; | |
| var params = { | |
| method: "post", | |
| contentType: "application/json", | |
| headers: headers, | |
| payload: JSON.stringify(request), | |
| muteHttpExceptions: true | |
| }; | |
| //var check = UrlFetchApp.getRequest(url, params); // for debugging | |
| var response = UrlFetchApp.fetch(url, params); | |
| var result = response.getResponseCode(); | |
| if (result == '200') { // OK | |
| return JSON.parse(response.getContentText()); | |
| } else { | |
| // This is only needed when muteHttpExceptions == true | |
| var err = JSON.parse(response.getContentText()); | |
| throw new Error('Error (' + result + ") " + err.error.message); | |
| } | |
| } | |
| /** | |
| * Get the Label ID for the given LabelName. If Label isn't found, it will be created | |
| * depending on the state of ok2Create. | |
| * Throws if unsuccessful. | |
| * See https://developers.google.com/gmail/api/v1/reference/users/messages/modify. | |
| * | |
| * @param {String} labelName Immutable Gmail Message ID to modify | |
| * @param {Boolean} ok2Create (optional) Set true if a label should be created when not found. | |
| * Default is true. | |
| * | |
| * @returns {String} ID of Label, or null if not found or created. | |
| */ | |
| function getLabelId(labelName, ok2Create) { | |
| if (typeof ok2Create == 'undefined') ok2Create = true; | |
| var id = null; | |
| // see https://developers.google.com/gmail/api/v1/reference/users/labels/list | |
| var url = 'https://www.googleapis.com/gmail/v1/users/${userId}/labels' | |
| .replace("${userId}", "me") // The user's email address. The special value me can be used to indicate the authenticated user. | |
| var headers = { | |
| Authorization: 'Bearer ' + ScriptApp.getOAuthToken() | |
| }; | |
| var params = { | |
| method: "get", | |
| contentType: "application/json", | |
| headers: headers, | |
| muteHttpExceptions: true | |
| }; | |
| //var check = UrlFetchApp.getRequest(url, params); // for debugging | |
| var response = UrlFetchApp.fetch(url, params); | |
| var result = response.getResponseCode(); | |
| if (result == '200') { // OK | |
| var labels = JSON.parse(response.getContentText()).labels; | |
| var found = false; | |
| for (var i = 0; i < labels.length & !found; i++) { | |
| if (labels[i].name == labelName) { | |
| found = true; | |
| id = labels[i].id; | |
| } | |
| } | |
| if (!found && ok2Create) { | |
| id = createLabel(labelName); | |
| } | |
| return id; | |
| } else { | |
| // This is only needed when muteHttpExceptions == true | |
| var err = JSON.parse(response.getContentText()); | |
| throw new Error('Error (' + result + ") " + err.error.message); | |
| } | |
| } | |
| /** | |
| * Create Label given LabelName. | |
| * Throws if unsuccessful. | |
| * See https://developers.google.com/gmail/api/v1/reference/users/messages/modify. | |
| * | |
| * @param {String} labelName Immutable Gmail Message ID to modify | |
| * | |
| * @returns {String} ID of Label. | |
| */ | |
| function createLabel(labelName) { | |
| var id = null; | |
| // see https://developers.google.com/gmail/api/v1/reference/users/labels/create | |
| var url = 'https://www.googleapis.com/gmail/v1/users/${userId}/labels' | |
| .replace("${userId}", "me") // The user's email address. The special value me can be used to indicate the authenticated user. | |
| var headers = { | |
| Authorization: 'Bearer ' + ScriptApp.getOAuthToken() | |
| }; | |
| var request = { | |
| 'name': labelName | |
| }; | |
| var params = { | |
| method: "post", | |
| contentType: "application/json", | |
| headers: headers, | |
| payload: JSON.stringify(request), | |
| muteHttpExceptions: true | |
| }; | |
| //var check = UrlFetchApp.getRequest(url, params); // for debugging | |
| var response = UrlFetchApp.fetch(url, params); | |
| var result = response.getResponseCode(); | |
| if (result == '200') { // OK | |
| var label = JSON.parse(response.getContentText()); | |
| id = label.id; | |
| return id; | |
| } else { | |
| // This is only needed when muteHttpExceptions == true | |
| var err = JSON.parse(response.getContentText()); | |
| throw new Error('Error (' + result + ") " + err.error.message); | |
| } | |
| } |
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <base target="_top"> | |
| </head> | |
| <body> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> | |
| <script> | |
| $(function() { | |
| print('Started processing e-mails.'); | |
| // Settings. | |
| var limit = 10; // Enable limit of emails to process. 0 to disable. | |
| var delay_between_reqs = 1000; // Delay between requests (in ms). | |
| var move_to_trash = true; // Move email to trash if successfully verified. | |
| var cors_proxy = '//cors-anywhere.herokuapp.com/'; // Link w/o "http:" or "https:", requires trailing slash. | |
| // Keep track. | |
| var emails = []; | |
| // Requests. | |
| function getRequest(item) { | |
| $.ajax({ | |
| url: item['url'] | |
| }).done(function(data, textStatus, xhr) { | |
| onRequestSuccess(item['id'], data, textStatus, xhr); | |
| }).fail(function(jqXHR, textStatus, errorThrown) { | |
| var status = jqXHR.status; | |
| if (status === 503) { | |
| err('PTC rate limit triggered, received a 503 response.'); | |
| } else { | |
| err('Request failed (' + status + '): ' + textStatus + '.'); | |
| } | |
| }); | |
| } | |
| // Callback. | |
| function onRequestSuccess(messageId, data, textStatus, xhr) { | |
| // Request successful. | |
| var status = xhr.status; | |
| if (status === 200) { | |
| // Expired verification link? | |
| var resend = data.match(/Resend your activation email/); | |
| var already_done = data.match(/account has already been activated/); | |
| var success = data.match(/Thank you for signing up! Your account is now active/); | |
| if (resend) { | |
| err('Expired verification link: ' + xhr.original_url + '.'); | |
| google.script.run.withSuccessHandler(labeledAsError).labelAsError(messageId, 'RM_EXPIRED'); | |
| } else if(already_done) { | |
| err('Account was already activated: ' + xhr.original_url + '.'); | |
| google.script.run.withSuccessHandler(labeledAsError).labelAsError(messageId, 'RM_PREACTIVATED'); | |
| } else if(success) { | |
| print('Account activated: ' + xhr.original_url + '.'); | |
| // Mark message as verified & optionally move to trash. | |
| google.script.run.markAsVerified(messageId, move_to_trash); | |
| } else { | |
| err('Unexpected reply on link: ' + xhr.original_url + '.'); | |
| } | |
| // Get next item. | |
| if (emails.length > 0) { | |
| print('Processing next email. Items left in queue: ' + emails.length + '.'); | |
| item = emails.pop(); | |
| // New request w/ min. delay. | |
| print('Sleeping ' + delay_between_reqs + 'ms until next request.'); | |
| setTimeout(function() { | |
| getRequest(item); | |
| }, delay_between_reqs); | |
| } else { | |
| print('Finished processing all emails.'); | |
| } | |
| } else { | |
| err('Unexpected response (' + status + '): ' + textStatus + '.'); | |
| } | |
| } | |
| // Go. | |
| function receivedEmailList(list) { | |
| print('Received ' + list.length + ' emails for verification.'); | |
| // Update global for callback handler. | |
| emails = list; | |
| // Stop if we have no results. | |
| if (emails.length === 0) { | |
| print('No unread PTC emails in inbox to verify.'); | |
| return; | |
| } | |
| // We have results. Set up AJAX for CORS proxy. | |
| setupCorsProxy(); | |
| // Time for requests. | |
| print('Starting first request.'); | |
| var item = emails.pop(); | |
| getRequest(item); | |
| } | |
| function setupCorsProxy() { | |
| var http = (window.location.protocol === 'http:' ? 'http:' : 'https:'); | |
| var proxy = http + cors_proxy; | |
| $.ajaxPrefilter(function(options) { | |
| if (options.crossDomain && jQuery.support.cors) { | |
| options.original_url = options.url; | |
| options.url = proxy + options.url; | |
| } | |
| }); | |
| $.ajaxSetup({ | |
| beforeSend: function(jqXHR, settings) { | |
| jqXHR.original_url = settings.original_url; | |
| } | |
| }); | |
| } | |
| function print(txt) { | |
| document.write('<p>' + txt + '</p>'); | |
| } | |
| function err(txt) { | |
| document.write('<p style="color: red;">' + txt + '</p>'); | |
| } | |
| function labeledAsError(response) { | |
| var success = response.success; | |
| if (!success) { | |
| err(JSON.stringify(response.error)); | |
| } | |
| } | |
| google.script.run.withSuccessHandler(receivedEmailList).getAllEmailLinks(limit); | |
| }); | |
| </script> | |
| </body> | |
| </html> |
@EFMEX505 Updated the script, you were doing nothing wrong and the script was working. It just reported these two things wrong:
Received 0 emails for verification.
Unexpected response (200): success.
These are now fixed and will report as expected.
It get stuck there.
PTC rate limit triggered, received a 503 response.
After 5 of processed emails
I have the same problem as masterThorn. It just hangs after "Started processing e-mails." I believe it may have something to do with the need to do something with AJAX or CORS setup, for which I haven't done any additional configuration. I have a good VPN and would be happy to not use CORS, but I tried // out the SetupCorsProxy(); and it still hangs at the same step. Suggestions?
Anyone manage to get it working? Can please share what steps taken? it just show "Started processing e-mails." and nothing else
@MerlionRock i found messing with the adjustable limit cooked it a few times, works a treat set to 10

everytime i try to run the new script all i get is:
Started processing e-mails. Received 0 emails for verification. Starting first request. Processing next email. Items left in queue: 8. Processing next email. Items left in queue: 7. Processing next email. Items left in queue: 6. Processing next email. Items left in queue: 5. Processing next email. Items left in queue: 4. Processing next email. Items left in queue: 3. Processing next email. Items left in queue: 2. Processing next email. Items left in queue: 1. Processing next email. Items left in queue: 0. Unexpected response (200): successany idea what im doing wrong?