質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.63%

for構文の回数が一回多くなる

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 512

TD0

score 16

お世話になります。
こちらのサイトを参考に、スプレッドシートに登録されている人にメールを一括送信するgasを組んでいます。
https://liapoc.com/bulk-transmission.html

実際に実行すると、メールは送信されますが、for 構文が最後の空の列を取得して終わります。
動作が一回分多いのですが、これをどう変更すればよろしいでしょうか?

よろしくお願いいたします。

function myFunction() {


var mySheet = SpreadsheetApp.getActive().getSheetByName('連絡先');
var rowSheet = mySheet.getDataRange().getLastRow(); 


var docTest=DocumentApp.openById("/*documentID*/"); 
var strDoc=docTest.getBody().getText();  

for(var i=2;i<=rowSheet;i++){
//for(var i=2;i<=rowSheet;i--){修正のご指摘をいただきました。

var strEmail=mySheet.getRange(i,1).getValue(); 
var strSei=mySheet.getRange(i,2).getValue();
var strMei=mySheet.getRange(i,3).getValue();

var strBody=strDoc.replace(/{姓}/g,strSei).replace(/{名}/g,strMei);


/* メール表題、fromアドレス、差出人名を準備 */
var strSubject = strSei + " " + strMei+"様 ●●●●●●●●"; //姓 名 様 メールタイトル
var strFrom="/*Mailadress*/"; //From
var strSender="/*Name*/"; //差出人


   /* メールを送信 */
    MailApp.sendEmail(
      strEmail, //toアドレス
      strSubject,  //メールタイトル
      strBody, //本文
      {
        from: strFrom, //fromアドレス
        name: strSender //差出人
      }
    ); 

  }
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • TD0

    2018/11/03 19:19

    すみません、++で実行しています^^;

    キャンセル

  • ikedas

    2018/11/03 19:21 編集

    質問本文を訂正してください。この追記・修正の依頼は隠れてしまうので、他の人が気づきません。

    キャンセル

  • TD0

    2018/11/03 19:30

    ご指摘ありがとうございました。

    キャンセル

回答 2

checkベストアンサー

+1

  • var rowSheet = mySheet.getDataRange().getLastRow();
    ikedas様が回答で引用された仕様のとおりなので、冗長です。var rowShet = myShet.getLastRow();とすべきです。
  • ロジックにより、ループが1回多くなる理由(今回はあてはまらないように見えるので参考程度に)
    手続型プログラミングでありがちなのは、forの終了条件の判定で、不等号でイコールを含むかどうかを誤っているパターン。これに対処するには、そもそもforをしない、という選択を考えるべきです。具体的にはArray.prototype.forEachを利用するなどをご検討ください。
  • 今回の1回多い理由と対処
    ロジック上の誤りには見えないので、データ起因です。つまり回答は自分で探すしかないです。そこで探しかた。
    どうやってループが1回多いと思ったかが疑問です。MailAppは、宛先が不正だとエラーになるので、仮にA列が空白だったら、メールは送信されないため(その後の実行も中断する)ので気付けないはず(例えばAからC列は5行しかデータがないのに、F6にタイプミスなどで文字があるときには、A6が空白なので、メール送信エラーで結局5通しか送信できない。あり得ないが送信できたとして、空白の宛先なので誰も知りようがない)。
    仮に、メールのあてさきや姓、名が同じものが2通来たことを根拠に判定しているとしても、それは行が非表示になっているなどして見えないだけで、ループが1回多いかどうか分からないはず。
    さらに、この2つの組み合わせとして、質問者様は3行と思っているのに、getLastRowは6を取得し、5行目のA列がないため、1回しか多くないようにみえてるパターンもあり得ます。
    などと考えると、gasが取得しているrowSheetやそれぞれの都度のstrEmailなどをLogger.logして見ていくほか原因も対処法も不明です
    (一般論として、strEmailなどが""だったらbreak/continueするというのは対処としてなくはないですが、メールが2通来ているパターンは対処できません)
  • A列の最終行を知りたい場合
    A,B,Cはペアなのでこれだけでは上手くいきませんが、A列にあるデータの個数(スプレッドシート関数で言うCOUNTA(A:A))は、下記のように取得できます。ただし、こちらはCOUNTA相当なので、途中にA列にデータがない行があると、A列のデータがある最終行を取得できない(足りなくなる)ので、ご注意ください。
function getLastRowOfA(sheet) {
  return sheet.getRange("A:A").getValues().filter(String).length; //"A:C"とやっても動かないのでご注意ください
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/11/04 00:06

    他の条件式についても順次勉強に励みます…

    ループが多いと気づいたきっかけは実行トランスクリプトからです。記載されているメールアドレス全てに確実にメールは送信されているため、確認をしたところ最後のメール送信の後、もう一度アドレス・姓名が空の状態で送信を試みていました。メールは正しく、一行一件送信されています。
    ご指摘の通りループが止まらない状態なのかもしれません。エラーが発生して強制的に終了しているだけなのかもしれないです…

    元データには空白等はありません。A列の最終行取得のアイデアを拝借して再構築してみます。

    キャンセル

  • 2018/11/05 08:41

    フォームの回答だと考えにくいですが、空白がある、のではなく使用していない列(Z列とか)に余計なデータがあるのでは、というのが推測です。
    確認方法としては
    Logger.log(mySheet.getDataRange().getValues())とすると取得した全データが見れるので思ったデータになっているか見てください

    キャンセル

  • 2018/11/05 10:59

    ご指摘の通り、行末にデータが含まれていました。
    (共同編集者がいたため、作成過程のメモを下欄に残していたようです。)
    大変丁寧にご指導いただいて、ありがとうございました。
    今後とも何卒よろしくおねがいいたします。

    キャンセル

+1

SheetのGetDataRange()の説明によると

This is functionally equivalent to creating a Range bounded by A1 and (Range.getLastColumn(), Range.getLastRow()).

説明がちょっとわかりにくいですが、mySheet.GetDataRange()は、シートの左上から、データが入っている一番右・一番下までの範囲を返すようです。ですから最終行より下 (左から3つめまでのセルとは限らない) にデータや関数が入っていたりすれば、mySheet.GetDataRange().getLastRow()はその行番号を返します。つまりmySheet.getLastRow()と同じになるようです。

特定の列だけを調べてデータが入っている最後の行を返すようなメソッドはないようです (あるのかもしれませんが私は見つけられませんでした)。不要なデータのあるセルを消すか、またはセルが空であれば繰り返しをやめるようにしてはどうでしょうか。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/11/03 23:59

    繰り返しをやめるという選択肢、検討してみます。
    次のステップとしてonFormsubmitのトリガー設定と、
    アドオンとしての公開を実践してみようとしていたため、
    mySheet.GetDataRange().getLastRow()を設定していました。
    (mySheet.getLast.Row()はご指摘の通り結果は同じだと把握しています。)

    特定列に絞れないんですね…セルに関しては一定規則のもとフォームから転送されるデータですので空は存在しないものとして構築しています。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.63%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる