# kintoneからgmailが送信できない

**URL:** <https://community.cybozu.dev/t/topic/8826>\
**Category:** kintone 開発相談\
**Created:** [2024 年 3 月 18 日午前 8:04 UTC](https://community.cybozu.dev/t/topic/8826 "2024-03-18T08:04:38Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![riogrande](https://avatars.discourse-cdn.com/v4/letter/r/ec9cab/32.png) [@riogrande](https://community.cybozu.dev/u/riogrande)\
**Post date:** [2024 年 3 月 18 日午前 8:04 UTC](https://community.cybozu.dev/t/topic/8826/1 "2024-03-18T08:04:38Z")

</div>

お世話になります。  
現在GCPを勉強中で、[Gmail 連携 - kintone から Gmail の送受信をしよう！ - cybozu developer network](https://cybozu.dev/ja/kintone/tips/development/3rd-party-services/mail/send-and-receive-gmail-from-kintone/)  
を参考にGmailとkintoneのapi連携をテスト実施しましたところ、送信がエラーになってしまう現象に接触しました。  
OAuth認証の画面では  
アカウントを選択後、 このアプリは Google で確認されていません  
になりますが画面左下の 詳細 クリックし  
認証をパスする形です。

> [@Gmailの送受信](https://community.cybozu.dev/t/topic/8765):
>
> Gmailを送受信できるようにしようと思い、 こちらのページの通りにやってみました。 一度は受信に成功して取り込めるのですが、 サイド取り込もうとすると受信失敗になってしまいます。 一度受診したレコードを全部消してみると、再受信できます。 どなたかお試しされた方いらっしゃいますでしょうか。ｌ

こちらのトピックに近い状況かと思いますが  
もし原因がお分かりになればお力添えいただきたく存じます。  
恐れ入りますが、よろしくお願いいたします。

(() =\> {  
‘use strict’;

// ログインのフラグ  
let tokenClient = false,  
isInitializeGapi = false,  
isInitializeGsi = false;

// 設定  
const AppSetting = {  
CLIENT\_ID: ‘クライアントIDを設定しています’,  
API\_KEY: ‘APIキーを設定しています’,  
DISCOVERY\_DOC: ‘[https://www.googleapis.com/discovery/v1/apis/gmail/v1/rest](https://www.googleapis.com/discovery/v1/apis/gmail/v1/rest)’,  
SCOPES: ‘[https://mail.google.com/](https://mail.google.com/)’,  
fieldsCode: {  
attachment: ‘attachment’,  
bcc: ‘bcc’,  
cc: ‘cc’,  
content: ‘message’,  
dateTime: ‘Date\_and\_time’,  
from: ‘from’,  
labels: ‘labels\_id’,  
mailAccount: ‘email\_account’,  
messageID: ‘message\_id’,  
owner: ‘owner’,  
subject: ‘subject’,  
threadID: ‘thread\_id’,  
to: ‘to’  
},  
profile: {emailAddress: ‘’},  
extensionProhibited: [  
‘ADE’, ‘ADP’, ‘BAT’, ‘CHM’, ‘CMD’, ‘COM’,  
‘CPL’, ‘DLL’, ‘DMG’, ‘EXE’, ‘HTA’, ‘INS’,  
‘ISP’, ‘JAR’, ‘JS’, ‘JSE’, ‘LIB’, ‘LNK’,  
‘MDE’, ‘MSC’, ‘MSI’, ‘MSP’, ‘MST’, ‘NSH’,  
‘PIF’, ‘SCR’, ‘SCT’, ‘SHB’, ‘SYS’, ‘VB’,  
‘VBE’, ‘VBS’, ‘VXD’, ‘WSC’, ‘WSF’, ‘WSH’  
],  
maxEmailSize: 5 \* 1024 \* 1024, // (byte) ~5MB  
maxMessagesForGet: 45,  
};

// スピナーを動作させる関数  
const showSpinner = ()=\> {  
// 要素作成等初期化処理  
if (document.getElementsByClassName(‘kintone-spinner’).length === 0) {  
// スピナー設置用要素と背景要素の作成  
const spnDiv = document.createElement(‘div’);  
spnDiv.id = ‘kintone-spin’;  
spnDiv.classList.add(‘kintone-spinner’);  
const spinBgDiv = document.createElement(‘div’);  
spinBgDiv.id = ‘kintone-spin-bg’;  
spinBgDiv.classList.add(‘kintone-spinner’);

```
  // スピナー用要素をbodyにappend
  document.body.appendChild(spnDiv);
  document.body.appendChild(spinBgDiv);

  // スピナーに対するオプション設定
  const opts = {
    lines: 11, // The number of lines to draw
    length: 38, // The length of each line
    width: 17, // The line thickness
    radius: 45, // The radius of the inner circle
    scale: 1, // Scales overall size of the spinner
    corners: 1, // Corner roundness (0..1)
    speed: 1, // Rounds per second
    rotate: 0, // The rotation offset
    animation: 'spinner-line-fade-more', // The CSS animation name for the lines
    direction: 1, // 1: clockwise, -1: counterclockwise
    color: '#000', // CSS color or array of colors
    fadeColor: 'transparent', // CSS color or array of colors
    top: '50%', // Top position relative to parent
    left: '50%', // Left position relative to parent
    shadow: '0 0 1px transparent', // Box-shadow for the lines
    zIndex: 2000000000, // The z-index (defaults to 2e9)
    className: 'spinner', // The CSS class to assign to the spinner
    position: 'absolute', // Element positioning
  };

  // スピナーを作動
  new Spinner(opts).spin(document.getElementById('kintone-spin'));
}

// スピナー始動（表示）
document.getElementById('kintone-spin-bg').style.display = 'block';
document.getElementById('kintone-spin').style.display = 'block';

```

};

// スピナーを停止させる関数  
const hideSpinner = () =\> {  
// スピナー停止（非表示）  
document.getElementById(‘kintone-spin-bg’).style.display = ‘none’;  
document.getElementById(‘kintone-spin’).style.display = ‘none’;  
};

// Googleログイン＆ログアウト  
const loadGapi = () =\> {  
gapi.load(‘client’, intializeGapiClient);  
};

const intializeGapiClient = async () =\> {  
await gapi.client.init({  
apiKey: AppSetting.API\_KEY,  
discoveryDocs: [AppSetting.DISCOVERY\_DOC],  
});  
isInitializeGapi = true;  
checkBeforeStart();  
};

const loadGsi = () =\> {  
tokenClient = google.accounts.oauth2.initTokenClient({  
client\_id: AppSetting.CLIENT\_ID,  
scope: AppSetting.SCOPES,  
callback: ‘’,  
});  
isInitializeGsi = true;  
checkBeforeStart();  
};

// ログイン準備ができたらログインボタン表示  
const checkBeforeStart = () =\> {  
if (isInitializeGapi && isInitializeGsi) {  
document.getElementById(‘loginButton’).style.visibility = ‘visible’;  
}  
};

// Googleログインボタンクリック  
const handleLoginClick = () =\> {  
tokenClient.callback = async (resp) =\> {  
if (resp.error !== undefined) {  
throw resp;  
}  
document.getElementById(‘logoutButton’).style.visibility = ‘visible’;  
document.getElementById(‘getMailButton’).style.visibility = ‘visible’;  
document.getElementById(‘loginButton’).innerText = ‘Refresh’;

```
  // プロフィールデータ取得
  AppSetting.profile.emailAddress = (await gapi.client.gmail.users.getProfile({userId: 'me'})).result.emailAddress;

};
if (gapi.client.getToken() === null) {
  tokenClient.requestAccessToken({prompt: 'consent'});
} else {
  tokenClient.requestAccessToken({prompt: ''});
}

```

};

// Googleログアウトボタンクリック  
const handleLogoutClick = () =\> {  
const token = gapi.client.getToken();  
if (token !== null) {  
google.accounts.oauth2.revoke(token.access\_token);  
gapi.client.setToken(‘’);  
document.getElementById(‘loginButton’).innerText = ‘Authorize’;  
document.getElementById(‘logoutButton’).style.visibility = ‘hidden’;  
document.getElementById(‘getMailButton’).style.visibility = ‘hidden’;  
}  
};

// メール送信  
const parseRecordDataToEmailData = (record) =\> {  
const result = {};  
for (const key in AppSetting.fieldsCode) {  
if (Object.prototype.hasOwnProperty.call(AppSetting.fieldsCode, key)) {  
const fieldCode = AppSetting.fieldsCode[key];  
result[key] = record[fieldCode].value;  
}  
}  
return result;  
};

// 送信メールBase64URLエンコード  
const encodeSender = (senderString) =\> {  
const senderArray = String(senderString).trim().split(‘,’);  
const senderResult = ;  
senderArray.forEach((sender) =\> {  
const patternSender = new RegExp(/(._)\<(._)\>/);  
const result = patternSender.exec(sender.trim());  
let email = ‘’;  
let emailEncoded = ‘’;  
if (result !== null && result.length === 3) {  
emailEncoded = encodeUTF8(result[1]) + ’ \<’ + result[2] + ‘\>’;  
email = result[2];  
} else {  
emailEncoded = sender;  
email = sender;  
}  
if (email === ‘’) {  
throw new Error(‘Emailアドレスが不正です。’);  
}  
senderResult.push(emailEncoded);  
});  
return senderResult.join(‘,’);  
};  
const encodeStringToBase64 = (string) =\> {  
return Encoding.base64Encode((new TextEncoder()).encode(string));  
};  
const encodeUTF8 = (string) =\> {  
return ‘=?UTF-8?B?’ + encodeStringToBase64(string) + ‘?=’;  
};  
const getByteOfString = (string) =\> {  
return encodeURI(string).split(/%…|./).length - 1;  
};  
const mineMessage = (data) =\> {  
const boundary = ‘kintoneBoundaryData’;  
const mineData = ;  
mineData.push(‘Content-Type: multipart/mixed; charset=“UTF-8”; boundary="’ + boundary + ‘"\r\n’);  
mineData.push(‘MIME-Version: 1.0\r\n’);  
if (data.from) {  
mineData.push(‘From: ’ + encodeSender(data.from) + ‘\r\n’);  
}  
if (data.to) {  
mineData.push(‘To: ’ + encodeSender(data.to) + ‘\r\n’);  
}  
if (data.cc) {  
mineData.push(‘Cc: ’ + encodeSender(data.cc) + ‘\r\n’);  
}  
if (data.bcc) {  
mineData.push(‘Bcc: ’ + encodeSender(data.bcc) + ‘\r\n’);  
}  
if (data.subject) {  
mineData.push(‘Subject: ’ + encodeUTF8(data.subject) + ‘\r\n\r\n’);  
}  
if (data.content) {  
mineData.push(’–’ + boundary + ‘\r\n’);  
mineData.push(‘Content-Type: text/html; charset=“UTF-8”\r\n’);  
mineData.push(‘MIME-Version: 1.0\r\n’);  
mineData.push(‘Content-Transfer-Encoding: 8bit\r\n\r\n’);  
mineData.push(data.content + ‘\r\n\r\n’);  
}  
if (data.attachment) {  
data.attachment.forEach((attach) =\> {  
mineData.push(’–’ + boundary + ‘\r\n’);  
mineData.push(‘Content-Type: ’ + attach.contentType + ‘\r\n’);  
mineData.push(‘MIME-Version: 1.0\r\n’);  
mineData.push(‘Content-Transfer-Encoding: base64\r\n’);  
mineData.push(‘Content-Disposition: attachment; filename="’ + attach.fileKey + ‘"’);  
});  
}  
mineData.push(’–’ + boundary + ‘–’);  
return mineData.join(‘’);  
};  
// 添付ファイルの拡張子を返す  
const getFileExtension = (fileName) =\> {  
if (!fileName) {  
return ‘’;  
}  
return String(fileName.split(‘.’).pop()).toUpperCase();  
};  
// レコードから送信メールデータを作成する  
const makeMailData = (mailData) =\> {  
let mineEmail = mineMessage(mailData);  
let hasAttachment = false;  
let mineEmailByte = getByteOfString(mineEmail);  
if (mailData.attachment && Array.isArray(mailData.attachment) && mailData.attachment.length \> 0) {  
hasAttachment = true;  
mailData.attachment.forEach((att) =\> {  
// 添付ファイルの拡張子チェック  
const fileExt = getFileExtension(att.name);  
if (AppSetting.extensionProhibited.indexOf(fileExt) \>= 0) {  
throw new Error(`${att.name}は添付できない拡張子のファイルです`);  
}  
// ファイルサイズ計算  
mineEmailByte += Number(att.size);  
mineEmailByte -= getByteOfString(att.fileKey);  
mineEmailByte += getByteOfString(att.name + ‘\r\n\r\n\r\n\r\n’);  
});  
}  
if (mineEmailByte \>= AppSetting.maxEmailSize) {  
throw new Error(‘メールの送信可能サイズを超えています。’);  
}  
// 添付ファイルがなければこの時点のmineEmailを返す  
if (hasAttachment === false) {  
return mineEmail;  
}  
// 添付ファイルが有れば、mineEmailに添付ファイルデータ分付け足して返す  
return downloadAttachments(mailData.attachment)  
.then((mailAttachments) =\> {  
mailAttachments.forEach((att) =\> {  
mineEmail = mineEmail.replace(‘"’ + att.fileKey + ‘"’, ‘"’ + att.name + ‘"\r\n\r\n’ + att.contentBytes + ‘\r\n\r\n’);  
});  
return mineEmail;  
});  
};

// kintoneの添付ファイルをダウンロードしてファイルデータをエンコードしたものを返す  
const downloadAttachments = (attachments) =\> {  
const attachmentPromise = ;  
for (let i = 0; i \< attachments.length; i++) {  
attachmentPromise.push(downloadAttachment(attachments[i]));  
}  
return kintone.Promise.all(attachmentPromise)  
.catch((error) =\> {  
console.log(error.message);  
});  
};

// kintoneの添付ファイルをダウンロードしてエンコードする  
const downloadAttachment = (kintoneFileData) =\> {  
const url = ‘/k/v1/file.json?fileKey=’ + kintoneFileData.fileKey;  
return new kintone.Promise((resolve, reject) =\> {  
const xhr = new XMLHttpRequest();  
xhr.open(‘GET’, url, true);  
xhr.setRequestHeader(‘X-Requested-With’, ‘XMLHttpRequest’);  
xhr.responseType = ‘arraybuffer’;  
xhr.onload = () =\> {  
kintoneFileData.contentBytes = encodeBufferToBase64(xhr.response);  
resolve(kintoneFileData);  
};  
xhr.onerror = (e) =\> {  
reject(e);  
};  
xhr.send();  
});  
};

// エンコード  
const encodeBufferToBase64 = (arraybuffer) =\> {  
let binary = ‘’;  
const bytes = new Uint8Array(arraybuffer);  
const len = bytes.byteLength;  
for (let i = 0; i \< len; i++) {  
binary += String.fromCharCode(bytes[i]);  
}  
return window.btoa(binary);  
};

// メール送信する  
const sendMail = async (record) =\> {  
try {  
// スピナー表示  
showSpinner();  
const emailAddress = (await gapi.client.gmail.users.getProfile({userId: ‘me’})).result.emailAddress;  
const mineEmail = await makeMailData(parseRecordDataToEmailData(record));  
const rawdata = Encoding.base64Encode((new TextEncoder()).encode(mineEmail)).replaceAll(‘/’, ‘\_’).replaceAll(‘+’, ‘-’);  
const dataEmailResponse = await gapi.client.gmail.users.messages.send({  
userId: ‘me’,  
resource: {raw: rawdata}  
});

```
  // メール送信後にレコードを更新する
  const updateRecordData = {};
  updateRecordData[AppSetting.fieldsCode.messageID] = {
    value: dataEmailResponse.result.id
  };
  updateRecordData[AppSetting.fieldsCode.threadID] = {
    value: dataEmailResponse.result.threadId
  };
  updateRecordData[AppSetting.fieldsCode.labels] = {
    value: dataEmailResponse.result.labelIds ? dataEmailResponse.result.labelIds.join(',') : ''
  };
  updateRecordData[AppSetting.fieldsCode.mailAccount] = {
    value: emailAddress
  };
  updateRecordData[AppSetting.fieldsCode.owner] = {
    value: [{
      code: kintone.getLoginUser().code,
      type: 'USER'
    }]
  };
  updateRecordData[AppSetting.fieldsCode.from] = {
    value: emailAddress
  };
  // レコード更新
  await kintone.api('/k/v1/record.json', 'PUT', {
    app: kintone.app.getId(),
    id: kintone.app.record.getId(),
    record: updateRecordData
  });
  location.reload();
  alert('メール送信完了');
} catch (error) {
  console.log(error.message);
  alert('メール送信失敗');
} finally {
  // スピナー非表示
  hideSpinner();
}

```

};

// メール受信  
const getBodyMessage = (dataParts, type) =\> {  
for (let index = 0; index \< dataParts.length; index++) {  
const bodyPart = dataParts[index];  
if (bodyPart.parts) {  
return getBodyMessage(bodyPart.parts, type);  
}  
const body = bodyPart.body.data || ‘’;  
if (bodyPart.mimeType === type) {  
return body;  
}  
}  
return ‘’;  
};

// メールのヘッダデータ取得  
const getHeaders = (arrayKeys, payloadData) =\> {  
const result = {};  
if (!arrayKeys || !Array.isArray(arrayKeys)) {  
return result;  
}  
for (let i = 0; i \< payloadData.headers.length; i++) {  
if (arrayKeys.indexOf(payloadData.headers[i].name) !== -1) {  
result[payloadData.headers[i].name.toLowerCase()] = payloadData.headers[i].value;  
}  
}  
return result;  
};

// メールの添付ファイルを取得  
const getAttachmentFiles = (payloadData) =\>{  
const fs = ;  
if (!payloadData.parts) {  
return fs;  
}

```
function getFiles(dataParts) {
  dataParts.forEach((part) => {
    if (part.parts) {
      return getFiles(part.parts);
    }
    if (part.filename !== '' && part.body.attachmentId) {
      fs.push(part);
    }
    return true;
  });
}

getFiles(payloadData.parts);
return fs;

```

};

// 受信メールから新規レコードを作成  
const makeKintonMailData = async (mid) =\> {  
const mailData = await gapi.client.gmail.users.messages.get({  
userId: ‘me’,  
id: mid,  
});

```
const result = {
  headers: getHeaders(['From', 'To', 'Cc', 'Bcc', 'Subject'], mailData.result.payload),
  fileKeys: [],
  mailInfo: {
    id: mid,
    threadId: mailData.result.threadId,
    labelIds: mailData.result.labelIds,
    date: mailData.result.internalDate,
  },
  profile: {
    emailAddress: AppSetting.profile.emailAddress,
  }
};

result.files = getAttachmentFiles(mailData.result.payload);

if (!mailData.result.payload.parts) {
  result.body = decodeMessage(mailData.result.payload.body.data, mailData) || '';
} else {

  const msgBody = getBodyMessage(mailData.result.payload.parts, 'text/html') || getBodyMessage(mailData.result.payload.parts, 'text/plain');
  result.body = decodeMessage(msgBody, mailData);
}
return addMailIntoKintone(result.mailInfo, result.headers, result.body, result.profile, result.files);

```

};

// kintoneにPOSTするリクエストボディのrecord情報作成  
const addMailIntoKintone = async (mailInfo, headers, body, profile, files) =\> {  
const kintoneRecord = {};  
kintoneRecord[AppSetting.fieldsCode.subject] = {  
value: headers.subject  
};  
kintoneRecord[AppSetting.fieldsCode.from] = {  
value: headers.from  
};  
kintoneRecord[AppSetting.fieldsCode.to] = {  
value: headers.to  
};  
kintoneRecord[AppSetting.fieldsCode.cc] = {  
value: headers.cc || ‘’  
};  
kintoneRecord[AppSetting.fieldsCode.bcc] = {  
value: headers.bcc || ‘’  
};  
const content = body;  
kintoneRecord[AppSetting.fieldsCode.content] = {  
value: content  
};  
kintoneRecord[AppSetting.fieldsCode.dateTime] = {  
value: (new Date(Number(mailInfo.date))).toISOString()  
};  
kintoneRecord[AppSetting.fieldsCode.threadID] = {  
value: mailInfo.threadId  
};  
kintoneRecord[AppSetting.fieldsCode.messageID] = {  
value: mailInfo.id  
};  
kintoneRecord[AppSetting.fieldsCode.labels] = {  
value: getLabelsStringForStorage(mailInfo.labelIds)  
};  
kintoneRecord[AppSetting.fieldsCode.mailAccount] = {  
value: profile.emailAddress  
};

```
kintoneRecord[AppSetting.fieldsCode.owner] = {
  value: [{
    code: kintone.getLoginUser().code,
    type: 'USER'
  }]
};

if (files && files.length > 0) {
  kintoneRecord[AppSetting.fieldsCode.attachment] = {
    value: await uploadFileToKintone(mailInfo.id, files, 0, []),
  };
}

return addNewRecord(kintoneRecord);

```

};

// POSTする  
const addNewRecord = (kintoneRecord) =\> {  
return kintone.api(‘/k/v1/record.json’, ‘POST’, {  
app: kintone.app.getId(),  
record: kintoneRecord  
});  
};

const getLabelsStringForStorage = (labelList) =\> {  
return labelList.filter((item) =\> {  
return [‘INBOX’, ‘SENT’].indexOf(item) \> -1;  
}).join(', ');  
};

// メールの添付ファイルをkintoneに保存できるようにエンコードする  
const encodeAttachmentBase64ToBlob = (base64String, contentType) =\> {  
const binary = decodeAttachment(base64String);  
const blob = new Blob([binary], {  
type: (contentType || ‘octet/stream’) + ‘;charset=utf-8;’  
});  
return blob;  
};

// 添付ファイルをkintoneにアップロードする  
const uploadFileToKintone = async (messageID, files, index, kintoneFilesKey) =\> {  
const file = files[index];

```
const attachment = await gapi.client.gmail.users.messages.attachments.get({
  id: file.body.attachmentId,
  messageId: messageID,
  userId: 'me',
});

// Create form file
const formFile = new FormData();
const blobFileAttachment = encodeAttachmentBase64ToBlob(attachment.result.data, file.mimeType);
formFile.append(' __REQUEST_TOKEN__', kintone.getRequestToken());
formFile.append('file', blobFileAttachment, file.filename);

const kintoneFileResponse = await uploadFile(kintone.api.url('/k/v1/file.json'), 'POST', formFile);
kintoneFilesKey.push(window.JSON.parse(kintoneFileResponse.response));

// POST files to kintone
if (index + 1 < files.length) {
  return uploadFileToKintone(messageID, files, index + 1, kintoneFilesKey);
}
return kintoneFilesKey;

```

};

// kintone にファイルをアップロードする  
const uploadFile = (url, method, formData, headers) =\> {  
return new kintone.Promise((resolve, reject) =\> {  
const xhrRequest = new XMLHttpRequest();  
xhrRequest.open(method, url);  
if (headers) {  
headers.forEach((header) =\> {  
if (header.key && header.value) {  
xhrRequest.setRequestHeader(header.key, header.value);  
}  
});  
}  
xhrRequest.setRequestHeader(‘X-Requested-With’, ‘XMLHttpRequest’);  
xhrRequest.onload = function() {  
if (xhrRequest.status === 200) {  
resolve(this);  
} else {  
reject(xhrRequest);  
}  
};  
xhrRequest.send(formData);  
});  
};

// メールの本文データをデコード  
const decodeMessage = (msg)=\>{  
return new TextDecoder().decode(new Uint8Array(Encoding.base64Decode(msg.replaceAll(‘\_’, ‘/’).replaceAll(‘-’, ‘+’))));  
};

// メールの添付ファイルをデコード  
function decodeAttachment(stringEncoded) {  
return new Uint8Array(Encoding.base64Decode(stringEncoded.replaceAll(‘\_’, ‘/’).replaceAll(‘-’, ‘+’)));  
}

// kintoneに保存していない受信メールのリストを取得  
const getPageOfMessages = async (allMsgList, dataRequest) =\>{  
const msgList = await gapi.client.gmail.users.messages.list(dataRequest);  
if (msgList.result.nextPageToken) {  
const nextDataRequest = dataRequest;  
nextDataRequest.pageToken = msgList.result.nextPageToken;  
return getPageOfMessages(allMsgList.concat(msgList.result.messages), nextDataRequest);  
}  
return allMsgList.concat(msgList.result.messages);  
};

// メール受信  
const getMails = async () =\> {  
try {  
// スピナー表示  
showSpinner();  
// メールリストから受診していないメールIDを取得  
const allList = await getPageOfMessages(, {  
userId: ‘me’,  
maxResults: 500,  
includeSpamTrash: false,  
});

```
  // メールが1件もなければエラー
  if (!allList || allList.length === 0) {
    throw new Error('No messages found.');
  }

  const rmsgIdArry = [];

  // レコード全件取得
  const client = new KintoneRestAPIClient();
  const allRecords = await client.record.getAllRecords({app: kintone.app.getId(), fields: [AppSetting.fieldsCode.messageID]});

  allRecords.forEach((r) => {
    rmsgIdArry.push(r[AppSetting.fieldsCode.messageID].value);
  });

  // まだ受診していないメールIDを最大45件取得
  const getMailIds = allList.filter(i => rmsgIdArry.indexOf(i.id) === -1).slice(0, AppSetting.maxMessagesForGet);

  const results = [];
  getMailIds.forEach(m=>{
    results.push(makeKintonMailData(m.id));
  });

  await Promise.all(results)
    .then((resp)=>{
      alert('メール受信成功！');
    });
} catch (error) {
  console.log(error.message);
  alert('メール受信失敗');
} finally {
  // スピナー非表示
  hideSpinner();
  location.reload();
}

```

};

// レコード一覧  
kintone.events.on(‘app.record.index.show’, (event) =\> {

```
const sp = kintone.app.getHeaderMenuSpaceElement();
// ボタンを作る
const loginButton = document.createElement('button');
loginButton.id = 'loginButton';
const logoutButton = document.createElement('button');
logoutButton.id = 'logoutButton';
const getMailButton = document.createElement('button');
getMailButton.id = 'getMailButton';
// ボタンに表示したいテキスト
loginButton.textContent = 'Gmailログイン';
logoutButton.textContent = 'Gmailログアウト';
getMailButton.textContent = 'メール受信';
// スペースフィールドにボタンを追加する
sp.appendChild(loginButton);
sp.appendChild(logoutButton);
sp.appendChild(getMailButton);
loginButton.style.visibility = 'hidden';
logoutButton.style.visibility = 'hidden';
getMailButton.style.visibility = 'hidden';
loginButton
  .addEventListener('click', handleLoginClick);
logoutButton
  .addEventListener('click', handleLogoutClick);
getMailButton
  .addEventListener('click', getMails);

// ログイン準備
loadGapi();
loadGsi();
return event;

```

});

// レコード詳細  
kintone.events.on(‘app.record.detail.show’, (event) =\> {

```
const sp = kintone.app.record.getHeaderMenuSpaceElement();
// ボタンを作る
const loginButton = document.createElement('button');
loginButton.id = 'loginButton';
const logoutButton = document.createElement('button');
logoutButton.id = 'logoutButton';
const sendMailButton = document.createElement('button');
sendMailButton.id = 'getMailButton';
// ボタンに表示したいテキスト
loginButton.textContent = 'Gmailログイン';
logoutButton.textContent = 'Gmailログアウト';
sendMailButton.textContent = 'メール送信';
// スペースフィールドにボタンを追加する
sp.appendChild(loginButton);
sp.appendChild(logoutButton);
sp.appendChild(sendMailButton);
loginButton.style.visibility = 'hidden';
logoutButton.style.visibility = 'hidden';
sendMailButton.style.visibility = 'hidden';
loginButton
  .addEventListener('click', handleLoginClick);
logoutButton
  .addEventListener('click', handleLogoutClick);
sendMailButton
  .addEventListener('click', sendMail.bind(null, event.record));

// ログイン準備
loadGapi();
loadGsi();
return event;

```

});

kintone.events.on([  
‘app.record.index.edit.show’,  
‘app.record.edit.show’,  
‘app.record.create.show’  
],  
(event) =\>{  
event.record[AppSetting.fieldsCode.from].disabled = true;  
if (event.type === ‘app.record.create.show’) {  
event.record[AppSetting.fieldsCode.from].value = ‘’;  
event.record[AppSetting.fieldsCode.threadID].value = ‘’;  
event.record[AppSetting.fieldsCode.labels].value = ‘’;  
event.record[AppSetting.fieldsCode.mailAccount].value = ‘’;  
event.record[AppSetting.fieldsCode.messageID].value = ‘’;  
event.record[AppSetting.fieldsCode.owner].value = [{  
code: kintone.getLoginUser().code  
}];  
}  
return event;  
});

})();

---

<div class="post-metadata">

**Author:** ![jurippe](https://sea1.discourse-cdn.com/flex015/user_avatar/community.cybozu.dev/jurippe/32/27_2.png) [@jurippe](https://community.cybozu.dev/u/jurippe)\
**Post date:** [2024 年 3 月 25 日午前 5:17 UTC](https://community.cybozu.dev/t/topic/8826/2 "2024-03-25T05:17:46Z")

</div>

記事のとおりに最初から設定してみましたが、メールの受信も送信も問題ありませんでした。  
もう一度ためしてみられてはいかがでしょうか！？👀！？

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/flex015/uploads/cybozu/original/1X/d5c841c3c5a6cb66eed514001c1b45147c9e1f4f.png) [@system](https://community.cybozu.dev/u/system)\
**Post date:** [2024 年 5 月 31 日午前 5:22 UTC](https://community.cybozu.dev/t/topic/8826/3 "2024-05-31T05:22:45Z")

</div>

このトピックはベストアンサーに選ばれた返信から 3 日が経過したので自動的にクローズされました。新たに返信することはできません。
