简体   繁体   English

如何使用谷歌应用程序脚本发送草稿电子邮件

[英]How to send a draft email using google apps script

I am working with Google apps script and would like to create a script which picks up mail from the drafts and sends them if they have label "send-tomorrow". 我正在使用谷歌应用程序脚本,并希望创建一个脚本,从草稿中提取邮件,如果标签为“明天发送”,则发送它们。 Finding drafts with a certain label is pretty simple: 查找带有特定标签的草稿非常简单:

 var threads = GmailApp.search('in:draft label:send-tomorrow');

However I don't see an API to send the message! 但是我没有看到用于发送消息的API! The only option I see is to: - open the message - extract body/attachments/title/from/to/cc/bcc - send a new message with the above params - destroy the previous draft 我看到的唯一选择是: - 打开消息 - 提取正文/附件/ title / from / to / cc / bcc - 发送带有上述参数的新消息 - 销毁之前的草稿

which seems pretty annoying and I'm not sure would work well with embedded images, multiple attachments etc... 这看起来很烦人,我不确定它是否适用于嵌入式图像,多个附件等...

any hint? 任何提示?

The only option I see is to: - open the message - extract body/attachments/title/from/to/cc/bcc - send a new message with the above params - destroy the previous draft 我看到的唯一选择是: - 打开消息 - 提取正文/附件/ title / from / to / cc / bcc - 发送带有上述参数的新消息 - 销毁之前的草稿

This is the exact topic of this blog by Amit Agarawal. 这是Amit Agarawal撰写的这篇博客的主题。 His script does just what you describe, but doesn't handle inline images. 他的脚本完全符合您的描述,但不处理内联图像。 For those, you can adapt the code from this article . 对于那些,您可以调整本文中的代码。

But you're right - what's the point of even having a draft message if you can't just send the stupid thing?! 但是你是对的 - 如果你不能发送愚蠢的东西,甚至有一条草稿信息的重点是什么?!

We can use the GMail API Users.drafts: send from Google Apps Script to send a draft. 我们可以使用GMail API Users.drafts:从Google Apps脚本发送以发送草稿。 The following stand-alone script does that, and handles the necessary authorization. 以下独立脚本执行此操作,并处理必要的授权。

Script 脚本

The full script is available in this gist . 完整的脚本可以在这个要点中找到

/*
 * Send all drafts labeled "send-tomorrow".
 */
function sendDayOldDrafts() {
  var threads = GmailApp.search('in:draft label:send-tomorrow');

  for (var i=0; i<threads.length; i++) {
    var msgId = threads[0].getMessages()[0].getId();
    sendDraftMsg( msgId );
  }
}


/**
 * Sends a draft message that matches the given message ID.
 * Throws if unsuccessful.
 * See https://developers.google.com/gmail/api/v1/reference/users/drafts/send.
 *
 * @param {String}     messageId   Immutable Gmail Message ID to send
 *
 * @returns {Object}               Response object if successful, see
 *                                 https://developers.google.com/gmail/api/v1/reference/users/drafts/send#response
 */
function sendDraftMsg( msgId ) {
  // Get draft message.
  var draftMsg = getDraftMsg(msgId,"json");
  if (!getDraftMsg(msgId)) throw new Error( "Unable to get draft with msgId '"+msgId+"'" );

  // see https://developers.google.com/gmail/api/v1/reference/users/drafts/send
  var url = 'https://www.googleapis.com/gmail/v1/users/me/drafts/send'
  var headers = {
    Authorization: 'Bearer ' + ScriptApp.getOAuthToken()
  };
  var params = {
    method: "post",
    contentType: "application/json",
    headers: headers,
    muteHttpExceptions: true,
    payload: JSON.stringify(draftMsg)
  };
  var check = UrlFetchApp.getRequest(url, params)
  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 );
  }
}


/**
 * Gets the current user's draft messages.
 * Throws if unsuccessful.
 * See https://developers.google.com/gmail/api/v1/reference/users/drafts/list.
 *
 * @returns {Object[]}             If successful, returns an array of 
 *                                 Users.drafts resources.
 */
function getDrafts() {
  var url = 'https://www.googleapis.com/gmail/v1/users/me/drafts';
  var headers = {
    Authorization: 'Bearer ' + ScriptApp.getOAuthToken()
  };
  var params = {
    headers: headers,
    muteHttpExceptions: true
  };
  var check = UrlFetchApp.getRequest(url, params)
  var response = UrlFetchApp.fetch(url, params);

  var result = response.getResponseCode();
  if (result == '200') {  // OK
    return JSON.parse(response.getContentText()).drafts;
  }
  else {
    // This is only needed when muteHttpExceptions == true
    var error = JSON.parse(response.getContentText());
    throw new Error( 'Error (' + result + ") " + error.message );
  }
}

/**
 * Gets the draft message ID that corresponds to a given Gmail Message ID.
 *
 * @param {String}     messageId   Immutable Gmail Message ID to search for
 *
 * @returns {String}               Immutable Gmail Draft ID, or null if not found
 */
function getDraftId( messageId ) {
  if (messageId) {
    var drafts = getDrafts();

    for (var i=0; i<drafts.length; i++) {
      if (drafts[i].message.id === messageId) {
        return drafts[i].id;
      }
    }
  }

  // Didn't find the requested message
  return null;
}


/**
 * Gets the draft message content that corresponds to a given Gmail Message ID.
 * Throws if unsuccessful.
 * See https://developers.google.com/gmail/api/v1/reference/users/drafts/get.
 *
 * @param {String}     messageId   Immutable Gmail Message ID to search for
 * @param {String}     optFormat   Optional format; "object" (default) or "json"
 *
 * @returns {Object or String}     If successful, returns a Users.drafts resource.
 */
function getDraftMsg( messageId, optFormat ) {
  var draftId = getDraftId( messageId );

  var url = 'https://www.googleapis.com/gmail/v1/users/me/drafts'+"/"+draftId;
  var headers = {
    Authorization: 'Bearer ' + ScriptApp.getOAuthToken()
  };
  var params = {
    headers: headers,
    muteHttpExceptions: true
  };
  var check = UrlFetchApp.getRequest(url, params)
  var response = UrlFetchApp.fetch(url, params);

  var result = response.getResponseCode();
  if (result == '200') {  // OK
    if (optFormat && optFormat == "JSON") {
      return response.getContentText();
    }
    else {
      return JSON.parse(response.getContentText());
    }
  }
  else {
    // This is only needed when muteHttpExceptions == true
    var error = JSON.parse(response.getContentText());
    throw new Error( 'Error (' + result + ") " + error.message );
  }
}

Authorization 授权

To use Google's APIs, we need to have an OAuth2 token for the current user - just as we do for Advanced Services. 要使用Google的API,我们需要为当前用户提供OAuth2令牌 - 就像我们为高级服务所做的那样。 This is done using ScriptApp.getOAuthToken() . 这是使用ScriptApp.getOAuthToken()

After copying the code to your own script, open Resources -> Advanced Google Services, open the link for the Google Developers Console, and enable the Gmail API for your project. 将代码复制到您自己的脚本后,打开资源 - >高级Google服务,打开Goog​​le Developers Console的链接,然后为您的项目启用Gmail API。

As long as the script contains at least one GMailApp method that requires user authority, the authentication scope will be set properly for the OAuthToken. 只要脚本包含至少一个需要用户权限的GMailApp方法,就会为OAuthToken正确设置身份验证范围。 In this example, that's taken care of by GmailApp.search() in sendDayOldDrafts() ; 在此示例中,由GmailApp.search()中的sendDayOldDrafts() ; but for insurance you could include a non-reachable function call directly in the functions using the API. 但是对于保险,您可以使用API​​直接在函数中包含不可访问的函数调用。

I did it using the GmailMessage.forward method. 我是使用GmailMessage.forward方法完成的。

It works with upload images and attachments, but I had to set the subject to avoid the prefix "Fwd:", and the user name because it only displayed the user email to the recipients. 它适用于上传图像和附件,但我必须设置主题以避免前缀“Fwd:”和用户名,因为它只向收件人显示用户电子邮件。

I didn't find a way to dispose the draft, so I just remove the label to prevent sending it again. 我没有找到处理草稿的方法,所以我只是删除标签以防止再次发送它。

Script: 脚本:

function getUserFullName(){
  var email = Session.getActiveUser().getEmail();
  var contact = ContactsApp.getContact(email);
  return contact.getFullName();
}

function testSendTomorrow(){
  var threads = GmailApp.search('in:draft label:send-tomorrow');

  if(threads.length == 0){
    return;
  }

  var labelSendTomorrow = GmailApp.getUserLabelByName("send-tomorrow");

  for(var i = 0; i < threads.length; i++){
    var messages = threads[i].getMessages();
    for(var j = 0; j < messages.length; j++){
      var mssg = messages[j];
      if(mssg.isDraft()){
        mssg.forward(mssg.getTo(), {
          cc: mssg.getCc(),
          bcc: mssg.getBcc(),
          subject: mssg.getSubject(),
          name: getUserFullName()
        });
      }
    }
    threads[i].removeLabel(labelSendTomorrow);
  }
}

You can search through all drafts and then send that specific draft no problem. 您可以搜索所有草稿,然后发送该特定草稿没问题。

function sendMessage(id){
  GmailApp.getDrafts().forEach(function (draft) {
    mes = draft.getMessage()
    if (mes.getId() == id) {
      draft.send()
    }
  })
}

A simpler alternative is to use the gmail api instead of gmailApp: 更简单的替代方法是使用gmail api而不是gmailApp:

function sendtestDraft(draftId){


  var request = Gmail.Users.Drafts.send({id : draftId},'me');


  Logger.log(request);

}

above function example is used within a gs script at https://script.google.com . 上面的函数示例在https://script.google.com的gs脚本中使用。 It needs the draftId (not the message Id) and the draft will be sent. 它需要draftId(而不是消息Id),草稿将被发送。 Images and attachments are all OK! 图像和附件都可以! Info: https://developers.google.com/gmail/api/v1/reference/users/drafts/send 信息: https//developers.google.com/gmail/api/v1/reference/users/drafts/send

I'm new around here and don't have enough "reputation" to comment, so couldn't comment on Mogsdad's original answer so I'm having to create a new answer: 我是新来的,没有足够的“声誉”来评论,所以无法对Mogsdad的原始答案发表评论,所以我不得不创建一个新的答案:

I've adapted Mogsdad's solution to also support replying/forwarding existing threads, not just brand new messages. 我已经改编了Mogsdad的解决方案,也支持回复/转发现有线程,而不仅仅是全新的消息。

To use it on existing threads, you should first create the reply/forward, and only then label the thread. 要在现有线程上使用它,首先应创建回复/转发,然后仅标记线程。 My code also supports several labels and setting up those labels. 我的代码还支持多个标签并设置这些标签。

I created a new gist for it, forking Mogsdad's, here: https://gist.github.com/hadasfester/81bfc5668cb7b666b4fd6eeb6db804c3 我为它创建了一个新的要点,在这里分享Mogsdad's: https ://gist.github.com/hadasfester/81bfc5668cb7b666b4fd6eeb6db804c3

I still need to add some screenshot links in the doc but otherwise this is ready for use, and I've been using it myself. 我仍然需要在文档中添加一些屏幕截图链接,否则这已经可以使用了,我自己一直在使用它。 Hope you find it useful. 希望你觉得它有用。

Also inlining it here: 同样在这里内联:

 /** * This script allows you to mark threads/drafts with a predetermined label and have them get sent the next time your trigger * sets off. * * Setup instructions: * 1. Make a copy of this script (File -> Make a copy) * 2. Follow the "Authorization" instructions on https://stackoverflow.com/a/27215474. (If later during setup/testing you get * another permissions approval dialog, approve there as well). * 2. I created two default labels, you can edit/add your own. See "TODO(user):" below. After that, to create them in gmail, * choose "setUpLabel" function above and click the play button (TODO: screenshot). Refresh your gmail tab, you should see * the new labels. * 3. Click the clock icon above (TODO: screenshot) and set time triggers, eg like so: (TODO: screenshot) * 4. I recommend also setting up error notifications: (TODO: screenshot). * * Testing setup: * When you're first setting this up, if you want to test it, create a couple * of drafts and label them. Then, in this * script, select "sendWeekStartDrafts" or "sendTomorrowDrafts" in the function dropdown * and press play. This manually triggers the script (instead of relying on the * timer) so you can see how it works. * * Usage instructions: * 1. To get a draft sent out on the next trigger, mark your draft with the label you chose. * NOTE: If your draft is a reply to a thread, make sure you first create the draft and only then set the label on the * thread, not the other way around. * That's it! Upon trigger your draft will be sent and the label will get removed from the thread. * * Some credits and explanation of differences/improvements from other existing solutions: * 1. This script was adapted from https://stackoverflow.com/a/27215474 to also support replying existing threads, not only * sending brand new messages. * 2. Other solutions I've run into are based on creating a new message, copying it field-by-field, and sending the new one, * but those have many issues, some of which are that they also don't handle replies and forwards very elegantly. * * Enjoy! **/ var TOMORROW_LABEL = '!send-tomorrow'; var WEEK_START_LABEL = '!send-week-start'; // TODO(user): add more labels here. /** * Set up the label for delayed send! **/ function setUpLabels() { GmailApp.createLabel(TOMORROW_LABEL); GmailApp.createLabel(WEEK_START_LABEL); // TODO(user): add more labels here. } function sendTomorrowDrafts() { sendLabeledDrafts(TOMORROW_LABEL); } function sendWeekStartDrafts() { sendLabeledDrafts(WEEK_START_LABEL); } // TODO(user): add more sendXDrafts() functions for your additional labels here. /* * Send all drafts labeled $MY_LABEL. * @param {String} label The label for which to send drafts. */ function sendLabeledDrafts(label) { var threads = GmailApp.search('in:draft label:' + label); for (var i=0; i<threads.length; i++) { var thread = threads[i]; var messages = thread.getMessages(); var success = false; for (var j=messages.length-1; j>=0; j--) { var msgId = messages[j].getId(); if (sendDraftMsg( msgId )) { success = true; } } if (!success) { throw Error( "Failed sending msg" ) }; if (success) { var myLabel = GmailApp.getUserLabelByName(label); thread.removeLabel(myLabel); } } } /** * Sends a draft message that matches the given message ID. * See https://developers.google.com/gmail/api/v1/reference/users/drafts/send. * * @param {String} messageId Immutable Gmail Message ID to send * * @returns {Object} Response object if successful, see * https://developers.google.com/gmail/api/v1/reference/users/drafts/send#response */ function sendDraftMsg( msgId ) { // Get draft message. var draftMsg = getDraftMsg(msgId,"json"); if (!getDraftMsg(msgId)) return null; // see https://developers.google.com/gmail/api/v1/reference/users/drafts/send var url = 'https://www.googleapis.com/gmail/v1/users/me/drafts/send' var headers = { Authorization: 'Bearer ' + ScriptApp.getOAuthToken() }; var params = { method: "post", contentType: "application/json", headers: headers, muteHttpExceptions: true, payload: JSON.stringify(draftMsg) }; var check = UrlFetchApp.getRequest(url, params) 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 return null; } } /** * Gets the current user's draft messages. * Throws if unsuccessful. * See https://developers.google.com/gmail/api/v1/reference/users/drafts/list. * * @returns {Object[]} If successful, returns an array of * Users.drafts resources. */ function getDrafts() { var url = 'https://www.googleapis.com/gmail/v1/users/me/drafts'; var headers = { Authorization: 'Bearer ' + ScriptApp.getOAuthToken() }; var params = { headers: headers, muteHttpExceptions: true }; var check = UrlFetchApp.getRequest(url, params) var response = UrlFetchApp.fetch(url, params); var result = response.getResponseCode(); if (result == '200') { // OK return JSON.parse(response.getContentText()).drafts; } else { // This is only needed when muteHttpExceptions == true var error = JSON.parse(response.getContentText()); throw new Error( 'Error (' + result + ") " + error.message ); } } /** * Gets the draft message ID that corresponds to a given Gmail Message ID. * * @param {String} messageId Immutable Gmail Message ID to search for * * @returns {String} Immutable Gmail Draft ID, or null if not found */ function getDraftId( messageId ) { if (messageId) { var drafts = getDrafts(); for (var i=0; i<drafts.length; i++) { if (drafts[i].message.id === messageId) { return drafts[i].id; } } } // Didn't find the requested message return null; } /** * Gets the draft message content that corresponds to a given Gmail Message ID. * See https://developers.google.com/gmail/api/v1/reference/users/drafts/get. * * @param {String} messageId Immutable Gmail Message ID to search for * @param {String} optFormat Optional format; "object" (default) or "json" * * @returns {Object or String} If successful, returns a Users.drafts resource. */ function getDraftMsg( messageId, optFormat ) { var draftId = getDraftId( messageId ); var url = 'https://www.googleapis.com/gmail/v1/users/me/drafts'+"/"+draftId; var headers = { Authorization: 'Bearer ' + ScriptApp.getOAuthToken() }; var params = { headers: headers, muteHttpExceptions: true }; var check = UrlFetchApp.getRequest(url, params) var response = UrlFetchApp.fetch(url, params); var result = response.getResponseCode(); if (result == '200') { // OK if (optFormat && optFormat == "JSON") { return response.getContentText(); } else { return JSON.parse(response.getContentText()); } } else { // This is only needed when muteHttpExceptions == true return null; } } 

First, GmailDraft now has a send() function you can call directly. 首先, GmailDraft现在有一个你可以直接调用的send()函数。 See: https://developers.google.com/apps-script/reference/gmail/gmail-draft#send() 请参阅: https//developers.google.com/apps-script/reference/gmail/gmail-draft#send()

Their code sample: 他们的代码示例:

var draft = GmailApp.getDrafts()[0]; // The first draft message in the drafts folder
var msg = draft.send(); // Send it
Logger.log(msg.getDate()); // Should be approximately the current timestamp

Second, may not even need it now that google has released scheduled sending. 其次,谷歌已经发布预定发送,甚至可能都不需要它。

  1. Click the arrow next to Send 单击“ Send旁边的箭头

单击“发送”旁边的向下箭头。

  1. Select your preferred time to send 选择您要发送的首选时间

选择您的首选时间。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用Google Apps脚本将Google文档文本导入电子邮件草稿 - How to Import Google doc text into Email draft using Google Apps Script 谷歌应用程序脚本添加一个组以草拟电子邮件 - google apps script adding a group to draft email 如何使用 GMAIL API 从 Google Apps 脚本发送电子邮件? - How to send the email from Google Apps Script using GMAIL API? 如何在 Google Apps 脚本中使用 MailApp 发送带有附件的 HTML email? - How to send a HTML email with attachment using MailApp in Google Apps Script? 如何使用谷歌应用程序脚本获取草稿消息的线程 ID - How to get the threadID for a draft message using google apps script 使用Google应用脚本创建草稿邮件 - Create draft mail using Google apps script Google Apps脚本[电子邮件发送] - Google Apps Script [Email Send] 如何使用Google Apps脚本代码创建草稿电子邮件(从985开始)? - How to use the Google Apps Script code for creating a Draft email (from 985)? 发送带有附件的电子邮件,并使用Google Apps脚本保存在Google云端硬盘中 - Send an email with attachment and save in Google Drive using Google Apps Script 如何在Google Apps脚本中发送带有变量的HTML电子邮件,并将其变量作为“发送至”地址 - How to send html email with variable as “send to” address in Google Apps Script
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM