Gmail ! Email , ! [2021]
Download File === https://bytlly.com/2sXFEf
This new setup experience for Gmail and Outlook will be enabled for Outlook for Microsoft 365 customers slowly over the next several weeks. If you don't see the exact screens shown here, see the topic Add an email account to Outlook for email setup instructions.
Student email, calendar and file storage/sharing services are moving from Google Suite (Gmail and Google Drive) to Microsoft 365 (Outlook and OneDrive). Learn more about the project at towson.edu/M365forStudents.
You create a Gmail draft template with placeholders thatcorrespond to data in a Sheets spreadsheet. Each column headerin a sheet represents a placeholder tag. The script sends the information foreach placeholder from the spreadsheet to the location of the correspondingplaceholder tag in your email draft.
: b/19236190 */ display: none; } .kd-tabbed-horz > article > pre { /* Remove extra spacing */ margin: 0; } devsite-selector > section[active] { /* Remove code section padding */ padding: 0; } .filepath { color: #fff; margin: 6px; max-width: calc(100% - 160px); /* Give at least 160px for the "View on GitHub" button. */ text-overflow: ellipsis; text-shadow: rgba(0,0,0,0.1) 1px 1px; overflow: hidden; } .view-on-github { text-shadow: rgba(12,12,12,0.1) 1px 1px; } .github-docwidget-include { border-radius: 0 !important; margin: 0 -1px; } solutions/automations/mail-merge/Code.js View on GitHub // To learn how to use this script, refer to the documentation:// -script/samples/automations/mail-merge/*Copyright 2022 Martin HawkseyLicensed under the Apache License, Version 2.0 (the "License");you may not use this file except in compliance with the License.You may obtain a copy of the License at -2.0Unless required by applicable law or agreed to in writing, softwaredistributed under the License is distributed on an "AS IS" BASIS,WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.See the License for the specific language governing permissions andlimitations under the License.*//** * @OnlyCurrentDoc*//** * Change these to match the column names you are using for email * recipient addresses and email sent column.*/const RECIPIENT_COL = "Recipient";const EMAIL_SENT_COL = "Email Sent";/** * Creates the menu item "Mail Merge" for user to run scripts on drop-down. */function onOpen() { const ui = SpreadsheetApp.getUi(); ui.createMenu('Mail Merge') .addItem('Send Emails', 'sendEmails') .addToUi();}/** * Sends emails from sheet data. * @param {string} subjectLine (optional) for the email draft message * @param {Sheet} sheet to read data from*/function sendEmails(subjectLine, sheet=SpreadsheetApp.getActiveSheet()) { // option to skip browser prompt if you want to use this code in other projects if (!subjectLine){ subjectLine = Browser.inputBox("Mail Merge", "Type or copy/paste the subject line of the Gmail " + "draft message you would like to mail merge with:", Browser.Buttons.OK_CANCEL); if (subjectLine === "cancel" || subjectLine == ""){ // If no subject line, finishes up return; } } // Gets the draft Gmail message to use as a template const emailTemplate = getGmailTemplateFromDrafts_(subjectLine); // Gets the data from the passed sheet const dataRange = sheet.getDataRange(); // Fetches displayed values for each row in the Range HT Andrew Roberts // -bulk-email-mail-merge-with-gmail-and-google-sheets-solution-evolution-using-v8/#comment-187490 // @see -script/reference/spreadsheet/range#getdisplayvalues const data = dataRange.getDisplayValues(); // Assumes row 1 contains our column headings const heads = data.shift(); // Gets the index of the column named 'Email Status' (Assumes header names are unique) // @see const emailSentColIdx = heads.indexOf(EMAIL_SENT_COL); // Converts 2d array into an object array // See // For a pretty version, see =17869/#comment-184945 const obj = data.map(r => (heads.reduce((o, k, i) => (o[k] = r[i] || '', o), {}))); // Creates an array to record sent emails const out = []; // Loops through all the rows of data obj.forEach(function(row, rowIdx){ // Only sends emails if email_sent cell is blank and not hidden by a filter if (row[EMAIL_SENT_COL] == ''){ try { const msgObj = fillInTemplateFromObject_(emailTemplate.message, row); // See -script/reference/gmail/gmail-app#sendEmail(String,String,String,Object) // If you need to send emails with unicode/emoji characters change GmailApp for MailApp // Uncomment advanced parameters as needed (see docs for limitations) GmailApp.sendEmail(row[RECIPIENT_COL], msgObj.subject, msgObj.text, { htmlBody: msgObj.html, // bcc: 'a.bbc@email.com', // cc: 'a.cc@email.com', // from: 'an.alias@email.com', // name: 'name of the sender', // replyTo: 'a.reply@email.com', // noReply: true, // if the email should be sent from a generic no-reply email address (not available to gmail.com users) attachments: emailTemplate.attachments, inlineImages: emailTemplate.inlineImages }); // Edits cell to record email sent date out.push([new Date()]); } catch(e) { // modify cell to record error out.push([e.message]); } } else { out.push([row[EMAIL_SENT_COL]]); } }); // Updates the sheet with new data sheet.getRange(2, emailSentColIdx+1, out.length).setValues(out); /** * Get a Gmail draft message by matching the subject line. * @param {string} subject_line to search for draft message * @return {object} containing the subject, plain and html message body and attachments */ function getGmailTemplateFromDrafts_(subject_line){ try { // get drafts const drafts = GmailApp.getDrafts(); // filter the drafts that match subject line const draft = drafts.filter(subjectFilter_(subject_line))[0]; // get the message object const msg = draft.getMessage(); // Handles inline images and attachments so they can be included in the merge // Based on // Gets all attachments and inline image attachments const allInlineImages = draft.getMessage().getAttachments({includeInlineImages: true,includeAttachments:false}); const attachments = draft.getMessage().getAttachments({includeInlineImages: false}); const htmlBody = msg.getBody(); // Creates an inline image object with the image name as key // (can't rely on image index as array based on insert order) const img_obj = allInlineImages.reduce((obj, i) => (obj[i.getName()] = i, obj) ,{}); //Regexp searches for all img string positions with cid const imgexp = RegExp(']+>', 'g'); const matches = [...htmlBody.matchAll(imgexp)]; //Initiates the allInlineImages object const inlineImagesObj = {}; // built an inlineImagesObj from inline image matches matches.forEach(match => inlineImagesObj[match[1]] = img_obj[match[2]]); return {message: {subject: subject_line, text: msg.getPlainBody(), html:htmlBody}, attachments: attachments, inlineImages: inlineImagesObj }; } catch(e) { throw new Error("Oops - can't find Gmail draft"); } /** * Filter draft objects with the matching subject linemessage by matching the subject line. * @param {string} subject_line to search for draft message * @return {object} GmailDraft object */ function subjectFilter_(subject_line){ return function(element) { if (element.getMessage().getSubject() === subject_line) { return element; } } } } /** * Fill template string with data object * @see * @param {string} template string containing {{}} markers which are replaced with data * @param {object} data object used to replace {{}} markers * @return {object} message replaced with data */ function fillInTemplateFromObject_(template, data) { // We have two templates one for plain text and the html body // Stringifing the object means we can do a global replace let template_string = JSON.stringify(template); // Token replacement template_string = template_string.replace(/{{[^{}]+}}/g, key => { return escapeData_(data[key.replace(/[{}]+/g, "")] || ""); }); return JSON.parse(template_string); } /** * Escape cell data to make JSON safe * @see * @param {string} str to escape JSON special characters from * @return {string} escaped string */ function escapeData_(str) { return str .replace(/[\\]/g, '\\\\') .replace(/[\"]/g, '\\\"') .replace(/[\/]/g, '\\/') .replace(/[\b]/g, '\\b') .replace(/[\f]/g, '\\f') .replace(/[\n]/g, '\\n') .replace(/[\r]/g, '\\r') .replace(/[\t]/g, '\\t'); };}
The sample code includes a number of additional parameters, currently commented out, that let you control the name of the account the email is sent from, reply to email addresses, as well as Bcc and Cc email addresses.
Automatically share emails, notes, and call logs with your team so you can pick up where they left off. Access pipeline data alongside your emails and from your pocket so you always have the context you need.
Find yourself typing the same emails over and over? Turn repetitive patterns into templates you can insert with one click, then personalize and optimize. Add more consistency to your communication with email templates for Gmail.
"I've used this for a while now and it's a life saver. Super easy way to send mass emails -- or just to send individual emails when you want to track if the person has opened it. Recommend it whole heartedly! Plus, it's extremely user friendly to use. I actually have a mailchimp subscription but i find that platform so fiddly, it ends up being easier to just use gmass."
"This tool is all you need when it comes to email automation! It works flowlessly, offers multiple useful features such as email verification before sending and is really worth the price. Tested for a couple of days and I love it so far!"
"As someone who has used Gmass for my own email outreach, I highly recommend it. What I love about this tool is how easy it is to personalize my mass emails and make them feel like one-on-one conversations with each recipient. The integration with Google Sheets and G Suite saves me a ton of time and makes my workflow much smoother. The email tracking and follow-up sequences are especially helpful and give me valuable insights into the effectiveness of my campaigns. The user interface is intuitive and the customer support team is always there to assist me if I need help. Overall, Gmass has been a game-changer for my email marketing efforts and I would definitely recommend it to anyone looking to streamline and personalize their outreach." 2b1af7f3a8