Google Apps Script sends wrong form input via mail - javascript

I am pretty new to coding and have the following problem with my little Google Apps Script.
Can anyone tell me why the following script doesn't send me/the user (I use the form and this script only myself) the specific answer of my latest form response? It somehow always sends me the answer of the form response with which I used this script the first time...
function sendAnswerViaMail() {
var myEmail = Session.getEffectiveUser().getEmail();
var subject = 'My answer to the 26th question.';
var form = FormApp.getActiveForm();
var formResponses = form.getResponses();
var formResponse = formResponses[formResponses.length-1];
var itemResponses = formResponse.getItemResponses();
var itemResponse = itemResponses[25];
MailApp.sendEmail (myEmail, subject, itemResponse.getResponse());
}

I suppose your script is fired when a user submit the form via the trigger functionnality.
The approach you have here is more logic one, but unfortunatelly not the good one because it does not handle the fact that 2 people may answer your form in almost the same time and the trigger that launch your script is not correlated with the fact that your script has recorded the answer and that you can access it with:
var form = FormApp.getActiveForm();
var formResponses = form.getResponses();
Instead of that approach I can propose you to use the object that the trigger on form submit will give to your function when launched:
/**
* function triggered each time the form is submited
*
*/
function submitFormFunc(e) {
var user = e.response.getRespondentEmail();
var items = e.response.getItemResponses();
var responses={}; // given responses form the user
var respObj = {};
for(var i = 0; i< items.length; i++) {
var it = items[i];
responses[it.getItem().getId()] = {
"title":it.getItem().getTitle(),
"response":it.getResponse()
};
respObj[it.getItem().getTitle()] = it.getResponse();
}
Logger.log("responses: "+JSON.stringify(responses));
}

Related

How to iterate on the links to google forms in the cells of a spreadsheet column to get their questions?

I have a Google spreadsheet with links to questionnaires. I wanted to know how to get the questions from each of the questionnaires.
I guess I have to do: at best, use the script editor and iterate on the lines, and at worst, do webscraping.
const puppeteer = require('puppeteer');
function appendString() {
var range = SpreadsheetApp.getActiveSheet().getActiveRange();
var numRows = range.getNumRows();
var numCols = 0;
for (var i = 1; i <= numRows; i++) {
for (var j = 1; j <= numCols; j++) {
var currentValue = range.getCell(i,j).getValue();
await page.goto(currentValue);
const pollFrame = page.frames().find() # From there I have some difficulties
}
}
}
But I get the following error:
SyntaxError: await is only valid in async function (ligne 10, fichier "Code.gs")
Not to mention the async problem or the buttonthat I still have to click, the selection looks like this:
<div class="freebirdFormviewerViewItemsItemItemTitle exportItemTitle freebirdCustomFont" id="i1" role="heading" aria-level="3" aria-describedby="i.desc.310938276">How often did you fly before the Covid-19 epidemic? </div>
But the IDs don't follow a logical numerical order, so I don't know how to extract them automatically.
Then I don't know how to do it. I wonder if it's simpler because they're products from the same supplier.
Here is the equivalent in csv format:
https://docs.google.com/forms/d/e/1FAIpQLSfzocEm6IEDKVzVGOlg8ijysWZyAvQur0NheJb_I_xozgKusA/viewform?usp=sf_link
https://docs.google.com/forms/d/e/1FAIpQLScrm0ZTrvlONf5MX37N93H_FajNzfbNy9ZtitX-Vq9PPuLPHA/viewform?usp=sf_link
https://docs.google.com/forms/d/e/1FAIpQLSeolFSh3OyS_XpX1lRIJP-8CH8WG0X0hL98SM9d85LqC22Bow/viewform?usp=sf_link
Update
So I tried the anwer kindly posted by Neven Subotic's:
// this array will store forms and their questions
let formAndQuestions = [];
let formIds = ["https://docs.google.com/forms/d/e/1FAIpQLSfzocEm6IEDKVzVGOlg8ijysWZyAvQur0NheJb_I_xozgKusA/viewform?usp=sf_link",
"https://docs.google.com/forms/d/e/1FAIpQLScrm0ZTrvlONf5MX37N93H_FajNzfbNy9ZtitX-Vq9PPuLPHA/viewform?usp=sf_link",
"https://docs.google.com/forms/d/e/1FAIpQLSeolFSh3OyS_XpX1lRIJP-8CH8WG0X0hL98SM9d85LqC22Bow/viewform?usp=sf_link"]
formIds.forEach( formId => {
const form = FormApp.openById( formId );
// lets get the name
const formName = form.getTitle();
// first we get all items
const allItemsInThisForm = form.getItems();
// then we get filter out anything that is not a questions
const allQuestionsInThisForm = allItemsInThisForm.filter( item => {
return isThisItemAQuestion( item )
});
// now we store them in our object
formAndQuestions.push( {
formId: formId,
formName: formName,
questions: allQuestionsInThisForm
})
});
// this function is used to only get the itemTypes you want
// see reference for more information
function isThisItemAQuestion( item ){
const itemType = item.getType();
const validQuestionItemTypes = [ FormApp.ItemType.TEXT, "add others here" ]
let isValid = false;
validQuestionItemsTypes.forEach( validItemType => {
if( itemType == validItemType ) {
isValid = true;
}
});
return isValid
}
Unfortunately I obtain the following error message with the following details Exception: No item with the given ID could be found, or you do not have permission to access it. (line 9, "const form = FormApp.openById( formId );"). I don't understand. As you can see in the gif, I can open these links, so I should have the permission to access them isn't it?
I also tried Ruben's ideas with:
// this array will store forms and their questions
let formAndQuestions = [];
let formIds = ["https://docs.google.com/forms/d/e/1FAIpQLSfzocEm6IEDKVzVGOlg8ijysWZyAvQur0NheJb_I_xozgKusA/viewform?usp=sf_link"]//,
//"https://docs.google.com/forms/d/e/1FAIpQLScrm0ZTrvlONf5MX37N93H_FajNzfbNy9ZtitX-Vq9PPuLPHA/viewform?usp=sf_link",
//"https://docs.google.com/forms/d/e/1FAIpQLSeolFSh3OyS_XpX1lRIJP-8CH8WG0X0hL98SM9d85LqC22Bow/viewform?usp=sf_link"]
function scrapeForms(){
formIds.forEach( formId => {
// The code below logs the HTML code of the Google home page.
var response = UrlFetchApp.fetch(formId);
results = response.getElementsByClassName("freebirdFormviewerViewItemsItemItemTitleContainer");
Logger.log(results.getContentText())
});
}
But got back:
TypeError: response.getElementsByClassName is not a function (ligne 13, fichier "Code")
According to What is this Javascript "require"? require is not part of the standard JavaScript an AFAIK it's not supported by Google Apps Script.
By the other hand, the error message can't be easily solved as Google Apps Script Chrome V8 engine doesn't support async functions. Related Is google apps script synchronous?
If you will be using Google Apps Script, and you are the form owner or a form editor, instead of trying to web scraping a Google Form use the Forms Service of Google Apps Script. For this you will need the form ../edit URLs instead of the ../viewform URLs. On the official docs there is a quickstart that might help you https://developers.google.com/apps-script/quickstart/forms.
You could use openByUrl to "open" a form. It will not be actually opened in your web browser, it will be opened on the server side. Then you could use getItems to get all the questions, sections, images, videos, etc.
If you aren't the form owner or a form editor then you should use UrlFetchApp service and somehow parse the web page source code of each form based on the position of the questions. Related question: Google Sheets: How to import the following data?
Also, if the form has several sections you should do a post request to emulate clicking on the next button in order to get the second and following sections. There are more "also if the form has..." but I will stop here as the main part of question was already answered, I think.
You first want to get all the forms, so place those in an array:
const formIds = ["someId", "anotherId", "andSoOn"]
Then, lets use the FormApp to get the form and all items. Items can be of different types, see documentation.
// this array will store forms and their questions
let formAndQuestions = [];
formIds.forEach( formId => {
const form = FormApp.openById( formId );
// lets get the name
const formName = form.getTitle();
// first we get all items
const allItemsInThisForm = form.getItems();
// then we get filter out anything that is not a questions
const allQuestionsInThisForm = allItemsInThisForm.filter( item => {
return isThisItemAQuestion( item )
});
// now we store them in our object
formAndQuestions.push( {
formId: formId,
formName: formName,
questions: allQuestionsInThisForm
}
});
// this function is used to only get the itemTypes you want
// see reference for more information
function isThisItemAQuestion( item ){
const itemType = item.getType();
const validQuestionItemTypes = [ FormApp.ItemType.TEXT, "add others here" ]
let isValid = false;
validQuestionItemsTypes.forEach( validItemType => {
if( itemType == validItemType ) {
isValid = true;
}
});
return isValid
}
Then you can initially log out the results and see what it looks like:
Logger.log( formAndQuestions )
Item Types

Google script project trigger not running?

I'm pretty new to Javascript and have been working on this script to take the most recent entry in a spreadsheet (created from a Google form), match the users email address that is collected to a roster in a second sheet, and send an email to parents. I'm a teacher and the idea is to be able to create a google form that compiles the info students enter and email it to their parents once they submit the form/update the sheet.
I know it's pretty messy...there are some extra variables and things, but the script works perfectly/as expected when you "Run" the script. The only thing is, I have tried to have the script run on a trigger when the form is submitted, but it doesn't. Am I missing something with using triggers?
Code is below:
function createEmail() {
// Sets variables for both sheets
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet1 = ss.getSheets()[0];
var sheet2 = ss.getSheets()[1];
// This gathers information from the most recent entry and write it to an array called newReflectionValues
var reflectionLastRow = sheet1.getLastRow();
var reflectionLastColumn = sheet1.getLastColumn();
var reflectionLastCell = sheet1.getRange(reflectionLastRow, reflectionLastColumn).getValue();
var reflectionRange = sheet1.getRange(reflectionLastRow, 1, 1, reflectionLastColumn);
var newReflectionValues = reflectionRange.getValues();
var studentEmail = newReflectionValues[0][3];
Logger.log("NEW REFLECTION VALUES")
Logger.log(newReflectionValues);
Logger.log("Email will send to student email:")
Logger.log(studentEmail)
// Makes an array of the parent email addresses
var rosterLastRow = sheet2.getLastRow();
var rosterLastColumn = sheet2.getLastColumn();
var rosterEmails = sheet2.getSheetValues(2, 1, rosterLastRow, rosterLastColumn);
Logger.log("PARENT EMAILS")
Logger.log(rosterEmails);
// Cross check emails - if a match, write emails to variable
var parentEntriesLength = rosterLastRow;
for (i = 0; i < parentEntriesLength; i++) {
var currentRange = rosterEmails[i];
if (currentRange[2] == studentEmail) {
var toParents = String(currentRange[3]) + ", " + String(currentRange[4]);
var studentName = String(currentRange[0]);
var countOfReflections = currentRange[6];
break;
} else {
var toParents = "NO PARENT EMAILS FOUND";
}
}
// FINISH EMAIL BELOW
MailApp.sendEmail({
to: toParents,
bcc: "rdoyle#rafos.org" + ", " + String(studentEmail),
subject: "Behavior Reflection Notification",
htmlBody: "<p>Hello,</p>" +
"<p>Today studentName received a behavior reflection for the following action:</p>" +
"<p>newReflectionValues</p>" +
"<p>They took a short break in class and completed the following reflection:</p>" +
"<p>reflectionInformation</p>" +
"<p>" + String(studentName) + " has recieved " + countOfReflections + " reflections this year." + "</p>" +
"<p>This email has been sent with information that the student completed directly on the reflection form and has been bcc'd to them as well as myself. If you have any questions regarding this behavior or incident, please feel free to ask.</p>"
});
}
You are aware that there are 2 types of trigger simple and installable but I think you are a little confused as to what they actually mean/ do. I'll try to explain the key points from documentation here.
A simple trigger is used by simply naming the function with the trigger name. For example, with Sheets / Forms, the trigger onFormSubmit(e) is fired when the user submits a form. The parameter e contains all the information relating to the submission, you should look into this as it's much more reliable than your current method of getting the submitted information. See here: 'e' parameter
Simple triggers are limited in their functionality since the script doesn't have to be authorised for the trigger to fire. A simple trigger cannot access other files, send emails or perform any action that requires authorisation. See here
An installed trigger is one that is either manually set up by the user or a script. Installed triggers have a lot more functionality but they still have some restrictions. See here
An installed trigger can call any named function and e parameter works in the same way as it does with simple triggers.
From your code above your installed trigger should look like this.
When you click save you should be asked for authorisation, if you are not asked, click the debug/ run button to authorise the script.
If it still doesn't work check the execution transcript in view -> execution transcript, the last line will indicate the error.
Ok, James helped out a lot, but I was seeming to have a lot of problems authenticating the permissions to send emails. I decided in the end to re-write everything more clearly, add some functions so others I work with could use the same script, and keep a record of whether or not emails were actually sent to parents. This final version uses a if statement to look in a column at whether or not an email was sent for each response, then sends an email if needed and records when it was sent. I also added a function to set up that "confirmation" column and create a roster sheet as a single function as well as seperately. Oh, and it also looks for an html template to format the email. I found that info on a Google developers live stream: https://www.youtube.com/watch?v=U9Ej6PCeO6s
Thanks everyone!
function createConfirmationColumn() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet1 = ss.getSheets()[0];
var lastColumn = sheet1.getLastColumn();
var lastColumnValue = sheet1.getRange(1,lastColumn).getValue();
// Creates the final column to log the time that emails are sent
if (lastColumnValue != "Email Sent On:") {
sheet1.insertColumnsAfter(lastColumn, 1);
var emailSentOnColumn = sheet1.getRange(1,lastColumn+1).setValue("Email Sent On:");
}
}
function createRosterSheet() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
ss.insertSheet("Roster & Parent Emails", 1);
var rosterSheet = ss.getSheets()[1];
rosterSheet.getRange(1,1).setValue("First Name")
rosterSheet.getRange(1,2).setValue("Last Name")
rosterSheet.getRange(1,3).setValue("Student Email")
rosterSheet.getRange(1,4).setValue("Parent Email 1")
rosterSheet.getRange(1,5).setValue("Parent Email 2")
rosterSheet.getRange(1,6).setValue("Notes")
rosterSheet.getRange(1,7).setValue("Total Reflections")
}
function formSetup() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet1 = ss.getSheets()[0];
var lastColumn = sheet1.getLastColumn();
var lastColumnValue = sheet1.getRange(1,lastColumn).getValue();
// Creates the final column to log the time that emails are sent
if (lastColumnValue != "Email Sent On:") {
sheet1.insertColumnsAfter(lastColumn, 1);
var emailSentOnColumn = sheet1.getRange(1,lastColumn+1).setValue("Email Sent On:");
}
ss.insertSheet("Roster & Parent Emails", 1);
var rosterSheet = ss.getSheets()[1];
rosterSheet.getRange(1,1).setValue("First Name")
rosterSheet.getRange(1,2).setValue("Last Name")
rosterSheet.getRange(1,3).setValue("Student Email")
rosterSheet.getRange(1,4).setValue("Parent Email 1")
rosterSheet.getRange(1,5).setValue("Parent Email 2")
rosterSheet.getRange(1,6).setValue("Notes")
rosterSheet.getRange(1,7).setValue("Total Reflections")
}
function sendEmails() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet1 = ss.getSheets()[0];
var sheet2 = ss.getSheets()[1];
var lastColumn = sheet1.getLastColumn();
var lastColumnValue = sheet1.getRange(1,lastColumn).getValue();
var allFormEntries = sheet1.getDataRange().getValues();
var allRosterValues = sheet2.getDataRange().getValues()
for (e = 1; e < sheet1.getLastRow(); e++) {
var formRange = allFormEntries[e];
var studentEmailInForm = formRange[1];
var emailSentOn = formRange[4];
if (emailSentOn == "") {
for (i = 1; i < sheet2.getLastRow(); i++) {
var individualRosterEntry = allRosterValues[i];
if (studentEmailInForm == individualRosterEntry[2]) {
var parentEmails = String(individualRosterEntry[3]) + ", " + String(individualRosterEntry[4]);
var emailTemplate = HtmlService.createTemplateFromFile("emailTemplate");
emailTemplate.studentName = individualRosterEntry[0];
emailTemplate.reflectionCount = individualRosterEntry[6];
emailTemplate.reason = formRange[2];
MailApp.sendEmail({
to: parentEmails,
bcc: "rdoyle#rafos.org" + ", " + String(studentEmailInForm),
subject: "Behavior Reflection Notification",
htmlBody: emailTemplate.evaluate().getContent(),
})
sheet1.getRange((e+1), lastColumn).setValue(new Date());
break;
} else {
sheet1.getRange((e+1), lastColumn).setValue("No valid email found") ;
}
} // for i loop
} //if email sent == ""
} //for e loop
} //function

How do I trigger events using Meteor server side events

I am using Meteor, which uses Mongodb as its database. I have code that inserts several documents into a collection when users fill out a form. When these documents are inserted, I would like to fire some JavaScript code within the server side directories that sorts through the collection in question for documents with matching fields as the documents just inserted.
My problem is that I do not know how to fire code on the server when the new documents arrive. Would it make sense to Meteor.call a Meteor.method at the end of the code involved with inserting, with the Meteor.method called preforming the sorting code I need?
Edit:
As you can see, in the below code I'm not calling any Meteor methods as none exist yet. The vast majority of this code is simply lead up for the insert({}) at the end of the page, so I think it can be safely ignored. The only server side code I have is to declare the possibleGames mongo collection.
I am not sure what you mean by call a plain JavaScript function, my problem is getting any code firing at all.
possibleGames = new Mongo.Collection("possibleGames");
Template.meet_form.events({
"submit .meet_form": function(event, template){
event.preventDefault();
var user = Meteor.userId();
var where = event.target.where.value;
var checkedGames = [];
function gameCheck (game) {
if (game.checked === true){
checkedGames.push(game.value);
};
};
var checkedDays = [];
function dayCheck (day) {
if (day.checked === true){
checkedDays.push(day.value);
};
};
console.log(event.target.where.value)
gameCheck(event.target.dnd);
gameCheck(event.target.savageWorlds);
gameCheck(event.target.shadowRun);
console.log(checkedGames);
dayCheck(event.target.monday);
dayCheck(event.target.tuesday);
dayCheck(event.target.wednesday);
dayCheck(event.target.thursday);
dayCheck(event.target.friday);
dayCheck(event.target.saturday);
dayCheck(event.target.sunday);
console.log(checkedDays);
var whereWhat = [];
for (i = 0; i < checkedGames.length; i++) {
var prepareWhereWhat = where.concat(checkedGames[i]);
whereWhat.push(prepareWhereWhat);
};
console.log(whereWhat);
var whereWhatWhen = [];
for (a = 0; a < whereWhat.length; a++) {
var prepareWWW1 = whereWhat[a];
for (b = 0; b < checkedDays.length; b++) {
var prepareWWW2 = prepareWWW1.concat(checkedDays[b]);
whereWhatWhen.push(prepareWWW2);
};
};
console.log(whereWhatWhen);
for (i = 0; i < whereWhatWhen.length; i++) {
possibleGames.insert({
game: whereWhatWhen[i],
user: user,
created_on: new Date().getTime()
})
}
}
});
You don't need to do a meteor.call on the server because you're already on the server.
Just call a plain javascript function.
If what you want to call from your first Meteor.method is already in another Meteor.method, then refactor that function to extract out the common bit.
Some code would also help if this is still confusing.

getting responseID of latest form submission in google apps

I have a google form. Every time it is submitted, the answers go into a google spreadsheet. I am trying to write an app script that triggers every time the form is submitted, and adds an "edit" link in the column to the right of the data from the form. The link itself is easy to generate, google has a method called getEditResponseURL(). (https://developers.google.com/apps-script/reference/forms/form-response)
But everytime I run it, I am getting the error "TypeError: Cannot call method "getResponses" of null."
Here is my code:
function addeditlink(e) {
// Get the active sheet
var sheet = SpreadsheetApp.getActiveSheet();
// Get the active row
var row = sheet.getActiveCell().getRowIndex();
//get the form
var form = FormApp.getActiveForm();
//get latest form response
var responses = form.getResponses();
var lastResponse = responses[responses.length - 1];
//get edit URL
var editurl = lastResponse.getEditResponseUrl();
//build link
var editlink = "Edit";
//place edit link in column R (index 18)
if (sheet.getRange(row, 18).getValue() == "") {
sheet.getRange(row, 18).setValue(editlink);
}
}
Any help? Thanks!
The solution is to remove:
var form = FormApp.getActiveForm(); //this is WRONG
and replace with:
var form = FormApp.openByID(' ID here ')
There is no "active form", because this script is being run in sheets, not forms.
I think you can only call FormApp.getActiveForm() from a script attached to a form, whereas your script is contained in a GSheet. I couldn't find a way to easily gets forms that used this sheet as its destination so what I've did was get all of the forms and then looked at the destination id of each and checked if it is the same as this spreadsheet. Once you've got your Form object you can get the responses. Feels a bit long winded would love to know if anyone knows a quicker way.
There are also a few exceptions that FormApp throws that you have to cope with.
Here's the function I use:
/**
* Find the first form that is linked to a specific spreadsheet
*
* #param {string} spreadsheet id
* #return {object} Form or null
*/
function getFormByDestinationId_(spreadsheetId) {
var formFiles = DriveApp.getFilesByType('application/vnd.google-apps.form');
var form;
var formFile;
var formId;
var destinationId;
while (formFiles.hasNext()) {
formFile = formFiles.next();
formId = formFile.getId();
// Throws an error if ID invalid
try {
form = FormApp.openById(formId);
} catch (error) {
if (error.name === "Exception") {
// Just ignore it
} else {
throw error;
}
}
// Form.getDestinationId() throws an error if there is no destination id
try {
destinationId = form.getDestinationId();
} catch (error) {
if (error.name === "Exception") {
// Just ignore it
} else {
throw error;
}
}
if (destinationId !== spreadsheetId) {
continue;
}
return form;
}
return null;
} // getFormByDestinationId_()
The only line using: getResponses() method is this one:
var responses = form.getResponses();
Your error:
Cannot call method "getResponses" of null
Means that form is null. If form is null, then this line:
//get the form
var form = FormApp.getActiveForm();
is not working. So, why isn't it working? There is nothing wrong with the code, so it must be a different problem. If there was an active form, that code would return a form type. This means that there is no form bound to the script. getActiveForm()
Returns the form to which the script is container-bound.
Your script is not "container-bound" to the form. Your script is bound to the spreadsheet.
The documentation states:
To interact with forms to which the script is not container-bound, use openById(id) or openByUrl(url) instead.
You can bind your script to the form by opening the script editor from the edit page of the form. But, there's no need to do that if you want to keep your script bound to the spreadsheet.
The line var form = FormApp.getActiveForm(); isn't going to work in your spreadsheet script.
The problem with using the Event Object e with an installable trigger, is that it looks like you can't get the response URL.
google_sheets_events
This means that you need to use openById(id) or openByUrl(url) inside the script bound to the spreadsheet, or move all your script to the form.
Here is how to get the edit url from script in the spreadsheet:
// Open a form by ID.
var form = FormApp.openById('1234567890abcdefghijklmnopqrstuvwxyz');
Now the problem is, that you can only get the Edit Response URL: getEditResponseUrl() through the "FormResponse" class. So you need the Form Responses.
var formResponses = form.getResponses();
But that's all the responses, you need the last one.
var lastResponseIndex = formResponses.length - 1;
var lastResponse = formResponses[lastResponseIndex];
var editURL = lastResponse.getEditResponseUrl();
or:
function getEditURLofLastResponse() {
// Open a form by ID.
var form = FormApp.openById('Your Form ID');
var formResponses = form.getResponses();
//get last respnse
var lastResponseIndex = formResponses.length - 1;
var lastResponse = formResponses[lastResponseIndex];
var editURL = lastResponse.getEditResponseUrl();
Logger.log(editURL);
}
Just an observation:
You are using an e argument: function addeditlink(e) {. But I don't see it being used in your code. That makes me wonder if you are using an "installable" trigger, as opposed to a "simple" trigger.
It's possible to get the values that were just submitted with e.values or e.namedValues. But you can't get the Edit URL with the Event Object.

Problem creating an email with an attachment in Javascript

I'm initiating an email create, by calling the code below, and adding an attachment to it.
I want the user to be able to type in the receipient, and modify the contents of the message, so I'm not sending it immediately.
Why do I get a RangeError the 2nd time the method is called?
(The first time it works correctly.)
function NewMailItem(p_recipient, p_subject, p_body, p_file, p_attachmentname)
{
try
{
var objO = new ActiveXObject('Outlook.Application');
var objNS = objO.GetNameSpace('MAPI');
var mItm = objO.CreateItem(0);
mItm.Display();
if (p_recipient.length > 0)
{
mItm.To = p_recipient;
}
mItm.Subject = p_subject;
if (p_file.length > 0)
{
var mAts = mItm.Attachments;
mAts.add(p_file, 1, p_body.length + 1, p_attachmentname);
}
mItm.Body = p_body;
mItm.GetInspector.WindowState = 2;
} catch(e)
{
alert('unable to create new mail item');
}
}
The error is occuring on the mAts.add line. So when it tries to attach the document, it fails.
Also the file name (p_file) is a http address to a image.
Won't work outside of IE, the user needs to have Outlook on the machine and an account configured on it. Are you sure you want to send an email this way?
I'm trying it with this little snippet, and it works flawlessly:
var objO = new ActiveXObject('Outlook.Application');
var mItm = objO.CreateItem(0);
var mAts = mItm.Attachments;
var p_file = [
"http://stackoverflow.com/content/img/vote-arrow-up.png",
"http://stackoverflow.com/content/img/vote-arrow-down.png"
];
for (var i = 0; i < p_file.length; i++) {
mAts.add(p_file[i]);
}
Note that I left off all optional arguments to Attachments.Add(). The method defaults to adding the attachments at the end, which is what you seem to want anyway.
Can you try this standalone snippet? If it works for you, please do a step-by-step reduction of your code towards this absolute minimum, and you will find what causes the error.
first do mItm.display()
then write mItm.GetInspector.WindowState = 2;
this will work

Categories