
Twilio SendGrid: Add or Update Contact (Custom Fields)
Twilio SendGrid: 宛先追加/更新(カスタムフィールド)
This item adds or updates a contact on SendGrid with the specified custom field values. If a contact with the specified email address already exists, the contact will be updated.
Basic Configs
- Step Name
- Note
Configs for this Auto Step
- conf_Auth
- C1: Authorization Setting in which API Key is set as token *
- conf_Email
- C2: Email Address *
- conf_FieldName1
- C3F: Custom Field Name 1
- conf_FieldValue1
- C3V: Value 1
- conf_FieldName2
- C4F: Custom Field Name 2
- conf_FieldValue2
- C4V: Value 2
- conf_FieldName3
- C5F: Custom Field Name 3
- conf_FieldValue3
- C5V: Value 3
- conf_FieldName4
- C6F: Custom Field Name 4
- conf_FieldValue4
- C6V: Value 4
- conf_FieldName5
- C7F: Custom Field Name 5
- conf_FieldValue5
- C7V: Value 5
- conf_FieldName6
- C8F: Custom Field Name 6
- conf_FieldValue6
- C8V: Value 6
- conf_FieldName7
- C9F: Custom Field Name 7
- conf_FieldValue7
- C9V: Value 7
- conf_FieldName8
- C10F: Custom Field Name 8
- conf_FieldValue8
- C10V: Value 8
Notes
- This item is intended for sendgrid.com
- It is not intended for sendgrid.kke.co.jp
- To learn about how to create your API Key, see the SendGrid Documentation
- When selecting Restricted Access, it is necessary to turn on the permission of Marketing


- To learn about the custom fields, see the SendGrid Documentation
- Data types of the custom field values should accord to the custom field types
Custom Field Type | Data Type |
Text | String (single line) |
Number | Numeric |
Date | Date (Y/M/D) |
Capture

See Also
Script (click to open)
- An XML file that contains the code below is available to download
- sendgrid-contact-upsert-custom-fields.xml (C) Questetra, Inc. (MIT License)
- If you are using Professional, you can modify the contents of this file and use it as your own add-on auto step
const FIELD_NUM = 8; // 扱えるフィールドの数
const MAX_EMAIL_LENGTH = 254;
const MAX_FIELD_VALUE_LENGTH = 1000;
function main(){
//// == Config Retrieving / 工程コンフィグの参照 ==
const auth = configs.get('conf_Auth');
const email = retrieveEmail();
const customFieldMap = retrieveCustomFieldsAsMap();
//// == Calculating / 演算 ==
const contact = {email};
if (customFieldMap.size > 0) {
const allCustomFields = getAllCustomFields(auth);
setCustomFields(contact, customFieldMap, allCustomFields);
}
const jobId = upsertContact(auth, contact);
// 処理状況を確認し、未完了なら proceed() に進む
if (checkStatus(auth, jobId) === false) {
engine.saveTemporaryData(jobId);
return false;
}
}
function proceed() {
//// == Config Retrieving / 工程コンフィグの参照 ==
const auth = configs.get('conf_Auth');
//// == Restoring Temporary Data / 一時データの読み出し ==
const jobId = engine.restoreTemporaryData();
if (jobId === null) {
throw 'Temporary data has not been saved.';
}
//// == 演算 / Calculating ==
if (checkStatus(auth, jobId) === false) {
return false;
}
}
/**
* config に設定されたメールアドレスを読み出す
* @return {String} email
*/
function retrieveEmail() {
const emailDef = configs.getObject('conf_Email');
const email = engine.findData(emailDef);
if (email === null) {
throw 'Email Address is blank.';
}
if (email.length > MAX_EMAIL_LENGTH) {
throw `Email Address must be within ${MAX_EMAIL_LENGTH} characters.`;
}
return email;
}
/**
* config に設定されたカスタムフィールドの情報を読み出す
* Map のキーはフィールド名、値はデータ定義
* @return {Map<String, DataDefinitionView>} customFieldMap
*/
function retrieveCustomFieldsAsMap() {
const customFieldMap = new Map();
for (let i = 0; i < FIELD_NUM; i++) {
const fieldName = configs.get(`conf_FieldName${i + 1}`);
const fieldValueDef = configs.getObject(`conf_FieldValue${i + 1}`);
if (fieldName === '' || fieldName === null) {
if (fieldValueDef !== null) { // フィールド名が空なのに、値のデータ項目が選択されている場合
throw `Custom Field Name ${i + 1} is blank while its value is selected.`;
}
continue;
}
if (customFieldMap.has(fieldName)) { // フィールド名の指定が重複
throw `Custom Field Name "${fieldName}" is set multiple times.`;
}
if (fieldValueDef === null) { // フィールド名は設定されているのに、値のデータ項目が選択されてない場合
// 「SendGrid: 宛先追加/更新」と仕様を合わせるため、null をセットせずにエラーにする
throw `Value ${i + 1} is not selected while its field name is set.`;
}
const dataObj = engine.findData(fieldValueDef);
// 文字型データを想定した文字数チェック。数値型、日付型データ以外が文字数制限に引っかかることはありえない
if (dataObj !== null && dataObj.toString().length > MAX_FIELD_VALUE_LENGTH) {
throw `Custom Field Value of "${fieldName}" must be within ${MAX_FIELD_VALUE_LENGTH} characters.`;
}
customFieldMap.set(fieldName, fieldValueDef);
}
return customFieldMap;
}
/**
* 全カスタムフィールドの一覧を取得する
* @param {String} auth 認証設定名
* @return {Array<Object>} allCustomFields
*/
function getAllCustomFields(auth) {
const response = httpClient.begin()
.authSetting(auth)
.get('https://api.sendgrid.com/v3/marketing/field_definitions');
const status = response.getStatusCode();
const responseStr = response.getResponseAsString();
if (status !== 200) {
engine.log(responseStr);
throw `Failed to get field definitions. status: ${status}`;
}
return JSON.parse(responseStr).custom_fields;
}
/**
* 宛先オブジェクトにカスタムフィールドの情報を追加する
* @param {Object} contact 宛先オブジェクト
* @param {Map<String, DataDefinitionView>} customFieldMap カスタムフィールドの Map
* @param {Array<Object>} allCustomFields 全カスタムフィールドの一覧
*/
function setCustomFields(contact, customFieldMap, allCustomFields) {
const customFields = {};
customFieldMap.forEach((dataDef, fieldName) => {
const customField = allCustomFields.find(field => field.name === fieldName);
if (customField === undefined) { // 指定したフィールド名のカスタムフィールドがない場合
throw `Custom Field named "${fieldName}" does not exist.`;
}
switch (customField.field_type) {
case 'Text':
addTextField(customFields, customField.id, customField.name, dataDef);
break;
case 'Number':
addNumberField(customFields, customField.id, customField.name, dataDef);
break;
case 'Date':
addDateField(customFields, customField.id, customField.name, dataDef);
break;
default:
// ありえないが、念のため
throw `Custom Field type "${customField.field_type}" is not supported.`;
}
});
Object.assign(contact, {custom_fields: customFields});
}
/**
* 文字型カスタムフィールドの情報を追加する
* @param {Object} customFields 設定するカスタムフィールド一覧
* @param {String} customFieldId カスタムフィールドの ID
* @param {String} customFieldName カスタムフィールドの名前(エラー出力用)
* @param {DataDefinitionView} dataDef データ定義
*/
function addTextField(customFields, customFieldId, customFieldName, dataDef) {
if (!dataDef.matchDataType('STRING_TEXTFIELD')) {
throw `Custom Field "${customFieldName}" is Text type. Its value must be set by STRING_TEXTFIELD type data item.`;
}
const dataObj = engine.findData(dataDef); // String or null
const fieldValue = dataObj ?? ''; // String
Object.assign(customFields, {[customFieldId]: fieldValue});
}
/**
* 数値型カスタムフィールドの情報を追加する
* @param {Object} customFields 設定するカスタムフィールド一覧
* @param {String} customFieldId カスタムフィールドの ID
* @param {String} customFieldName カスタムフィールドの名前(エラー出力用)
* @param {DataDefinitionView} dataDef データ定義
*/
function addNumberField(customFields, customFieldId, customFieldName, dataDef) {
if (!dataDef.matchDataType('DECIMAL')) {
throw `Custom Field "${customFieldName}" is Number type. Its value must be set by DECIMAL type data item.`;
}
const dataObj = engine.findData(dataDef); // BigDecimal or null
let fieldValue = '';
if (dataObj !== null) {
fieldValue = dataObj.doubleValue();
}
Object.assign(customFields, {[customFieldId]: fieldValue});
}
/**
* 日付型カスタムフィールドの情報を追加する
* @param {Object} customFields 設定するカスタムフィールド一覧
* @param {String} customFieldId カスタムフィールドの ID
* @param {String} customFieldName カスタムフィールドの名前(エラー出力用)
* @param {DataDefinitionView} dataDef データ定義
*/
function addDateField(customFields, customFieldId, customFieldName, dataDef) {
if (!dataDef.matchDataType('DATE_YMD')) {
throw `Custom Field "${customFieldName}" is Date type. Its value must be set by DATE_YMD type data item.`;
}
const dataObj = engine.findData(dataDef); // AddableDate or null
let fieldValue = '';
if (dataObj !== null) {
fieldValue = dateFormatter.format('MM/dd/yyyy', dataObj);
}
Object.assign(customFields, {[customFieldId]: fieldValue});
}
/**
* 宛先を追加/更新する
* @param {String} auth 認証設定名
* @param {Object} contact 宛先情報
* @return {String} jobId
*/
function upsertContact(auth, contact) {
const requestBody = {
"contacts": [contact]
};
const response = httpClient.begin()
.authSetting(auth)
.body(JSON.stringify(requestBody), 'application/json')
.put('https://api.sendgrid.com/v3/marketing/contacts');
const status = response.getStatusCode();
const responseStr = response.getResponseAsString();
if (status !== 202) {
engine.log(responseStr);
throw `Failed to upsert contact. status: ${status}`;
}
return JSON.parse(responseStr).job_id;
}
/**
* ジョブの処理状況を確認する
* @param {String} auth 認証設定名
* @param {String} jobId ジョブ ID
* @return {boolean} true: 完了, false: 未完了
*/
function checkStatus(auth, jobId) {
const response = httpClient.begin()
.authSetting(auth)
.get(`https://api.sendgrid.com/v3/marketing/contacts/imports/${jobId}`);
const status = response.getStatusCode();
const responseStr = response.getResponseAsString();
if (status !== 200) {
engine.log(responseStr);
throw `Failed to get upsert status. status: ${status}`;
}
const jobStatus = JSON.parse(responseStr).status;
switch (jobStatus) {
case 'pending': // 処理中
return false;
case 'completed': // 完了
return true;
default: // errored or failed
engine.log(responseStr);
throw 'Failed to complete upserting the contact.';
}
}