【问题标题】:Sendgrid v3 not working for me with rails my_mailer.rbSendgrid v3 不适用于我使用 rails my_mailer.rb
【发布时间】:2019-11-19 21:48:36
【问题描述】:

我想在用户注册时通过 Sendgrid 发送交易邮件(我使用设计进行身份验证)。我使用 SMTP 在 my_mailer.rb 中正常工作,如下所示:

  def confirmation_instructions(record, token, opts={})
    # SMTP header for Sendgrid - v2
    # headers["X-SMTPAPI"]= {
    #  "sub": {
    #    "-CONFIRM_TOKEN-": [
    #      token
    #    ]       
    #   },
    #  "filters": {
    #   "templates": {
    #     "settings": {
    #       "enable": 1,
    #       "template_id": "1111111-1111-1111-1111-111111111111"
    #     }
    #   }
    #  }   
    # }.to_json    

但是,Sendgrid 提示使用 v3 语法来支持较新的邮件模板,我将代码更改为以下内容(来自 sendgrid 帮助文档,而不是真正的理解):

  def confirmation_instructions(record, token, opts={})

    require 'sendgrid-ruby'
    include SendGrid

    sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY'])

    data = JSON.parse('{
      "substitutions": {
        "-CONFIRM_TOKEN-": [
          token
        ],
      "template_id": "1111111-1111-1111-1111-111111111111"
    }')

    response = sg.client.mail._("send").post(request_body: data)
    puts response.status_code
    puts response.body
    puts response.parsed_body
    puts response.headers    

现在我收到错误消息:
'NoMethodError (undefined method `include' for #<MyMailer:0x0000000003cfa398>):'

如果我注释掉“包含”行,我会得到:
'TypeError (no implicit conversion of nil into String):' on the line: "sg = SendGrid..."

我使用 Gem:sendgrid-ruby (5.3.0)

任何想法都将不胜感激 - 我一直在尝试通过反复试验来找到正确的语法,但最终承认我被卡住了。

更新#1:
第一个问题是我使用了错误的 API_KEY 环境。变量(从 2 个不同的帮助文档中复制):“SENDGRID_API_KEY”(在代码中)与 SENDGRID_APIKEY_GENERAL(在 Heroku 中设置)。固定。

更新 #2:
注释掉“include”行后,我现在似乎遇到了 JSON 解析错误:

JSON::ParserError (416: unexpected token at 'token

所以我现在的 2 个问题是:
(1) 我希望 'token' 成为确认令牌变量,但它没有被传递

(2) 发送以下简单(1 行)的 'data' 内容不会引发错误,但未选择 Sendgrid 中的相应模板:

data = JSON.parse('{
  "template_id": "1111111-1111-1111-1111-111111111111"    
}')

更新 #3:
以下是我的问题状态的更新以及我现在卡住的确切位置:

此代码运行良好(使用我尝试升级的 Sendgrid v2):

  def confirmation_instructions(record, token, opts={})

    #
    # SMTP header for Sendgrid     - v2
    #     This works fine
    #

    headers["X-SMTPAPI"]= {
     "sub": {
       "-CONFIRM_TOKEN-": [
         token
       ]
      },
     "filters": {
      "templates": {
        "settings": {
          "enable": 1,
          "template_id": "1111111-1111-1111-1111-111111111111"
        }
      }
     }
    }.to_json 

此 Sendgrid v3 代码不起作用(电子邮件确实通过 Sendgrid 发送,但它没有选择 Sendgrid 中的模板 - 它只是使用 app/views/my_mailer/confirmation_instructions.html.erb 中的任何代码):

    #
    # Sendgrid API v3
    #   This sends an email alright but it takes content from app/views/my_mailer/confirmation_instructions.html.erb
    #   It DOES NOT select the template within Sendgrid
    #

    data = JSON.parse('{
      "template_id": "1111111-1111-1111-1111-111111111111",
      "personalizations": [
        {
          "substitutions": {
            "-CONFIRM_TOKEN-": "'+token+'"
          } 
        }
      ]
    }')

    sg = SendGrid::API.new(api_key: ENV['SENDGRID_APIKEY_GENERAL2'])
    response = sg.client.mail._("send").post(request_body: data)
    puts response.status_code
    puts response.body
    puts response.parsed_body
    puts response.headers

一如既往,任何见解都值得赞赏。

【问题讨论】:

  • 您应该提出一个新问题,而不是更新已回答的问题。此外,如果您觉得自己得到了帮助,您应该接受并投票赞成答案:-)
  • 我试图支持你的答案,因为它是一个帮助(解决特定的“包含”问题),但我没有足够的声誉这样做。此外,我最初的问题仍未解决,即获取一个与 SendGrid v3 一起使用的事务动态模板。与此同时,我已经取得了一些进展,我现在将记录下来,作为帮助其他人做同样事情的答案。
  • 我更新了我的答案,我认为您在使用 JSON.parse 时犯了一个错误,并且您实际上并没有从您的控制器调用正确的邮件方法。

标签: ruby-on-rails ruby devise sendgrid sendgrid-api-v3


【解决方案1】:

对于任何试图让 SendGrid v3 API 与 Ruby/Devise/Heroku 一起使用并使用 SendGrid 的动态事务电子邮件的人,这些提示可能会对您有所帮助。我花了一周的时间让这个工作,这些步骤(和我犯的错误)在各种文档中并不明显:

  1. 生成SendGrid API 密钥(在SendGrid 网站上):生成密钥时,API 密钥只出现一次,允许您复制它,此后就看不见了。由于后来我看不到密钥,我错误地在 Heroku 环境变量中使用了“API 密钥 ID”,而不是真正的 API 密钥。

  2. 确保您在 Heroku 中提供的密钥名称(对我来说:“SENDGRID_APIKEY_GENERAL”)与您用来引用它的代码相匹配,即 sg = SendGrid::API.new(api_key: ENV['SENDGRID_APIKEY_GENERAL'])

  3. 要发送要在模板中替换的变量,请使用“dynamic_template_data”而不是“substitutions”。这应该在“个性化”部分(参见下面的代码示例)。

  4. 我发现通过在 Heroku 中使用环境变量(对我来说:'SENDGRID_TRANS_EMAIL_CONFIRM_TEMPLATE_ID')而不是在 Ruby 中进行硬编码来引用 Sendgrid 动态模板 ID 很有用(只是允许我尝试使用不同的模板而不是更改代码)。

  5. 在 Ruby 中使用 JSON 字符串中的变量的正确语法是例如"CONFIRM_TOKEN": "'+token+'"(见下面的代码示例)

  6. 请勿在名称中使用其他字符:即“CONFIRM_TOKEN”有效但“-CONFIRM_TOKEN-”无效

  7. 在 SendGrid 交易电子邮件模板的 HTML 中,使用以下语法进行替换:{{CONFIRM_TOKEN}}

  8. 在 SendGrid 上创建事务模板时,您只能拥有“设计”视图或“代码”视图,不能同时拥有两者。创建模板时必须在开始时选择,之后不能切换。

  9. 在设计confirmations_instructions 操作中,将用户作为记录(例如电子邮件)称为record.email

  10. Gemfile: gem 'rails', '5.2.2' ruby '2.6.1' gem 'devise', '4.6.1 ' gem 'sendgrid-ruby', '6.0.0'

这是我在 my_mailer.rb 中成功的 ruby​​ 代码:

  def confirmation_instructions(record, token, opts={})

    data = JSON.parse('{
      "personalizations": [
        {
          "to": [
            {
              "email": "'+record.email+'"
            }
          ],
          "subject": "Some nice subject line content",
          "dynamic_template_data": {
            "CONFIRM_TOKEN": "'+token+'",
            "TEST_DATA": "hello"
          }
        }
      ],
      "from": {
        "email": "aaaa@aaaa.com"
      },
      "content": [
        {
          "type": "text/plain",
          "value": "and easy to do anywhere, even with Ruby"
        }
      ],
      "template_id": "'+ENV['SENDGRID_TRANS_EMAIL_CONFIRM_TEMPLATE_ID']+'"
    }')

    sg = SendGrid::API.new(api_key: ENV['SENDGRID_APIKEY_GENERAL'])
    response = sg.client.mail._("send").post(request_body: data)
    puts response.status_code
    puts response.body
    puts response.headers

【讨论】:

    【解决方案2】:

    您不能include 方法中的模块。你必须将它包含在你的类中,所以在方法之外,比如

    class SomethingMailer
      require 'sendgrid-ruby'
      include SendGrid
    
      def confirmation_instructions(record, token, opts={})
        ...
      end
    end
    

    第三次更新问题:

    您不是在发送 JSON,而是在创建 JSON,然后将其解析为哈希,然后发送该哈希,而不是 JSON。

    JSON.parse #parses a JSON into a Hash
    

    你应该做相反的事情,并有一个你可以转换成 JSON 的哈希

    类似

    data = {
      template_id: your_template_id # or pass a string
      personalizations: [
        ...
      ]
    }
    

    然后你打电话

    data_json = data.to_json
    response = sg.client.mail._("send").post(request_body: data_json)
    

    但这并不能解释为什么您在app/views/my_mailer/confirmation_instructions.html.erb 中的模板会被发送。所以我认为您要么同时调用不同的 mailer_method,要么根本没有调用实际的 confirm_instructions 方法。尝试确认您确实调用了 SendGrid 方法并查看它返回的内容。当您发送哈希而不是字符串时,它应该已经返回了某种错误。

    【讨论】:

    • 谢谢 - 我相应地更新了我的代码。根据我的更新 #3 的最新问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多