GmailApp.sendEmail() won't send email with a Bitly URL in body - google-apps-script

I have a Google apps script which sends an email with a long URL and a Bitly shortened one. However the GmailApp.sendEmail function silently fails if I include a Bitly URL. Simple example of problem code:
function myFunction() {
var sMail = "(my email address)";
var longURL = "https://www.google.com";
var shortURL = "(bitly URL)";
// Send email with information
GmailApp.sendEmail(
sMail,
"URL Send Test",
"Original URL: " + longURL + "\n" +
"Short URL: " + shortURL
);
}
This code executes without error, but I never receive the email or any notification that it was blocked. If I remove shortURL from the body then email is received.
Obviously these shortened links are a source of abuse (in fact I can't include it in my post) but is there a way around this? My script generates a long custom URL and shortening it is an important function.
Thanks for any suggestions.

Related

How to forward a Gmail email and add to the message body using GmailApp in Google Apps Script?

The GmailMessage.forward only has an htmlBody option. But if you use that, then the forwarded email does not include the original email's body/content. It only includes what you put in htmlBody.
How can I forward the email, add text, and include the original body?
var message = GmailApp.search(`...`)[0].getMessages()[0];
message.forward("...", {
"htmlBody" : "hi"
});
You would need to get the body of the message you are looking to forward:
function myFunction() {
const message = GmailApp.search(`to:...#gmail.com`)[0].getMessages()[0];
const forwarded = message.getBody(); // that is the body of the message we are forwarding.
message.forward("....#hotmail.com", {
"htmlBody" : "My email test?<br><br>" //adds your message to the body
+
"<div style='text-align: center;'>---------- Forwarded message ----------</div><br>" + forwarded, //centers
});
}
I made a sample code based on yours by searching messages that were sent to a specific email address and forwarding to a hotmail email address.
Edit:
Reference code and the importance of getting the body of the email can be found over this thread

Limiting OAuth scope for Google App Script

I am trying to limit my OAuth scopes in my script that sends an email after a form has been submitted. I want to limit it so that it has the least permission needed. If I click run, it tries to authorize the correct permissions. If I set up the on form submit trigger, it wants to authorize read, change, delete on all spreadsheets and change on all forms.
If I give the script full access to sheets and forms, it runs as intended. I just want to reduce some of the permissions. The screenshot shows that it is asking for more permission than what is specified in the appsscript.json file.
This script is attached to the responses sheet generated from my form.
From my appsscript.json:
"oauthScopes": [
"https://www.googleapis.com/auth/gmail.readonly",
"https://www.googleapis.com/auth/gmail.send",
"https://www.googleapis.com/auth/drive.file",
"https://www.googleapis.com/auth/forms.currentonly",
"https://www.googleapis.com/auth/spreadsheets.currentonly"
]
The code:
/**
* #OnlyCurrentDoc
*/
function onFormSubmit(e) {
var values = e.namedValues;
var htmlBody = 'Hey ' + values['Name of Recipient'] + "!<br>";
htmlBody += values['Name of Sender'] + " thinks you deserve a shoutout! Thank you for being so awesome!";
htmlBody += '<br> <em>' + values['Shoutout'] + " - " + values['Name of Sender'] + "</em>";
htmlBody += '<br><br>';
GmailApp.sendEmail(values['Recipient Email'],'SHOUT OUT!!!!!!','',
{from:'email#domain.com',
htmlBody:htmlBody});
}
Google Form/Sheet Questions/Columns
Timestamp
Name of Sender
Name of Recipient
Name of Recipient's Boss
Shoutout
Recipient Email
Recipient's Boss Email
OAuth Permissions Screenshot:
Project Details OAuth Scopes:
View your email messages and settings https://www.googleapis.com/auth/gmail.readonly
Send email on your behalf https://www.googleapis.com/auth/gmail.send
See, edit, create, and delete only the specific Google Drive files you use with this app https://www.googleapis.com/auth/drive.file
View and manage forms that this application has been installed in https://www.googleapis.com/auth/forms.currentonly
View and manage spreadsheets that this application has been installed in https://www.googleapis.com/auth/spreadsheets.currentonly
By default, See, edit, create, and delete all your Google Sheets spreadsheets is a required scope if you added an Installable Trigger that has event source of From Spreadsheet and View and manage your forms in Google Drive is also added if the event type is On form submit. This is to give script the access to the changes that may happen in the spreadsheet caused by submitting response. As a result, it will return the user an Event Object containing information about the context that caused the trigger to fire.
The script will also work if you manually press Run but there is no Event Object that will be passed to the function parameter.
You can try using Time-driven as event source and it will show the same scope as you declared in appsscript.json since the trigger doesn't need to access the spreadsheet to execute the trigger.
Example:
Time Driven:
From spreadsheet and On Open:
From spreadsheet and On form submit:
References:
Event Object
Installable Triggers
I believe your goal is as follows.
From your question, you want to restrict the scopes for your showing script of The code: as follows.
/**
* #OnlyCurrentDoc
*/
function onFormSubmit(e) {
var values = e.namedValues;
var htmlBody = 'Hey ' + values['Name of Recipient'] + "!<br>";
htmlBody += values['Name of Sender'] + " thinks you deserve a shoutout! Thank you for being so awesome!";
htmlBody += '<br> <em>' + values['Shoutout'] + " - " + values['Name of Sender'] + "</em>";
htmlBody += '<br><br>';
GmailApp.sendEmail(values['Recipient Email'],'SHOUT OUT!!!!!!','',
{from:'email#domain.com',
htmlBody:htmlBody});
}
It seems that when GmailApp.sendEmail of Gmail Service is used, the scope is constant as https://mail.google.com/. It seems that this is the current specification. So when you want to restrict the scopes, I think that you can achieve it using Gmail API. When your script is converted using Gmail API, it becomes as follows.
Modified script:
Before you use this script, please enable Gmail API at Advanced Google services.
/**
* #OnlyCurrentDoc
*/
// This is from https://stackoverflow.com/a/66088350
function convert_(toEmail, fromEmail, subject, textBody, htmlBody) {
const boundary = "boundaryboundary";
const mailData = [
`MIME-Version: 1.0`,
`To: ${toEmail}`,
`From: ${fromEmail}`,
`Subject: =?UTF-8?B?${Utilities.base64Encode(subject, Utilities.Charset.UTF_8)}?=`,
`Content-Type: multipart/alternative; boundary=${boundary}`,
``,
`--${boundary}`,
`Content-Type: text/plain; charset=UTF-8`,
``,
textBody,
``,
`--${boundary}`,
`Content-Type: text/html; charset=UTF-8`,
`Content-Transfer-Encoding: base64`,
``,
Utilities.base64Encode(htmlBody, Utilities.Charset.UTF_8),
``,
`--${boundary}--`,
].join("\r\n");
return Utilities.base64EncodeWebSafe(mailData);
}
function onFormSubmit(e) {
var htmlBody = 'Hey ' + values['Name of Recipient'] + "!<br>";
htmlBody += values['Name of Sender'] + " thinks you deserve a shoutout! Thank you for being so awesome!";
htmlBody += '<br> <em>' + values['Shoutout'] + " - " + values['Name of Sender'] + "</em>";
htmlBody += '<br><br>';
var raw = convert_(values['Recipient Email'], 'email#domain.com', 'SHOUT OUT!!!!!!', "", htmlBody);
Gmail.Users.Messages.send({raw: raw}, "me");
}
In this script, only tne scope of https://www.googleapis.com/auth/gmail.send can be used.
In this sample script, it supposes that e is the correct value you want to use. Please be careful about this.
Note:
About other scopes of "https://www.googleapis.com/auth/gmail.readonly", "https://www.googleapis.com/auth/drive.file", "https://www.googleapis.com/auth/forms.currentonly", "https://www.googleapis.com/auth/spreadsheets.currentonly", when I saw your script, those scopes are not required to be used. But, when Google Form is used, https://www.googleapis.com/auth/forms.currentonly might be required to be used. Please be careful this.
For example, when you want to use other methods, please add the scopes for them. My answer is for your showing script in your question. Please be careful about this.
Reference:
Method: users.messages.send

How to stop MailApp.sendEmail from sending myself a copy of the email

We are using Google Scripts to send emails after Google Forms are submitted. In the last day or two, we started receiving email delivery failures every time a form was submitted and the script ran. It is only unable to deliver messages to one account(sender#mydomain.com), which happens to be the account that the script is running as. However, this account should not be receiving a copy of this form anyways. All of the email addresses that are in the "To" field are getting the email with no issue, we are just trying to find out why we are getting this error message.
We are using the MailApp.sendEmail function and have been for years without any problem. We can't use the GmailApp functions because this account is not able to use Gmail and we've never needed to be able to in order to send emails.
In the script, when I add sender#mydomain.com to the To list, I receive the email and do not get any error messages. When I remove it from the To list, the rest of the recipients continue to receive the email but I get that error message again for sender#mydomain.com.
function formSubmitReply(e) {
var replyToAddr = "no_reply#mydomain.com";
var emailAddress = e.values[2]; // + ", sender#mydomain.com";
//Removed section that creates PDF, stores as the variable pdf
var subject = "Form Request from " + e.values[1];
var messageHtml = "<font size = 3><font face = arial>Form Request from: " + e.values[1];
var messagePlain = messageHtml.replace(/\<br\/\>/gi, '\n').replace(/(<([^>]+)>)/ig, "");
MailApp.sendEmail(emailAddress, subject, messagePlain, {htmlBody: messageHtml, name: "Sender", attachments: pdf, replyTo: replyToAddr});
}
It sounds weird to me that MailApp was working on an account that doesn't have Gmail enabled as MailApp affects the email sent Gmail quota but then I found No reports a 550 recipient rejected from MailApp. The only answer at this time looks to be wrong as MailApp sent emails are saved as sent emails on Gmail mailbox of the effective user that ran the script.

Formatting removed for google docs embed in gmail via app script

I have a scenario where I need to schedule an email at particular time every-day but the content of an email is present in some google doc and update on timely bases. So currently I am manually sending email and paste those content into my email but I want to automate the same.
So by doing search I found, it can be possible via google apps-script and I have written some script as below :
var id = '<my_Id>';
var url = "https://docs.google.com/feeds/download/documents/export/Export?id="+id+"&exportFormat=html";
var param = {
method : "get",
headers : {"Authorization": "Bearer " + ScriptApp.getOAuthToken()},
contentType: "text/html",
muteHttpExceptions:true,
};
var html = UrlFetchApp.fetch(url,param).getContentText();
MailApp.sendEmail(email, 'DSR', 'html only', {htmlBody:html});
Script is working fine and I can see the contents into email but the google doc has some formatting like back-ground, foreground color, table but in email it is shows as only plain text.
Thanks.
This works for me.
https://gist.github.com/erickoledadevrel/11143648
the problem is html has to be inline
Thanks.

Google Apps Script - inline images example doesn't work

I'm trying to get this example script working from this Google Developer page.
I put the below code, which is copy/pasted verbatim (except for the "recipient#example.com" of course) into a function which runs when a form is submitted.
// This code fetches the Google and YouTube logos, inlines them in an email
// and sends the email
function inlineImage() {
var googleLogoUrl = "http://www.google.com/intl/en_com/images/srpr/logo3w.png";
var youtubeLogoUrl = "https://developers.google.com/youtube/images/YouTube_logo_standard_white.png";
var googleLogoBlob = UrlFetchApp
.fetch(googleLogoUrl)
.getBlob()
.setName("googleLogoBlob");
var youtubeLogoBlob = UrlFetchApp
.fetch(youtubeLogoUrl)
.getBlob()
.setName("youtubeLogoBlob");
MailApp.sendEmail({
to: "recipient#example.com",
subject: "Logos",
htmlBody: "inline Google Logo<img src='cid:googleLogo'> images! <br>" +
"inline YouTube Logo <img src='cid:youtubeLogo'>",
inlineImages:
{
googleLogo: googleLogoBlob,
youtubeLogo: youtubeLogoBlob
}
});
}
The email is not sent at all and the code doesn't appear to execute.
When I remove the first 4 statements (setting up the URLs and blobs), and the inlineImages section of the sendEmail function, the email is sent.
What am I doing wrong?
I have no problem with your code.