Sendgrid v3无法与Rails my_mailer.rb一起使用

时间:2019-07-10 09:37:12

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

我想在用户注册时通过Sendgrid发送交易邮件(我使用devise进行身份验证)。我在my_mailer.rb中使用SMTP的情况如下:

  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>):'

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

我使用宝石:sendgrid-ruby(5.3.0)

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

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

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

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

所以我现在有2个问题:
 (1)我希望“令牌”成为确认令牌变量,但未传递

(2)发送以下简单的“数据”内容(1行)不会引发错误,但是未选择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

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

2 个答案:

答案 0 :(得分:0)

您不能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,要么根本没有调用实际的Confirmation_instructions方法。尝试确认您确实调用了SendGrid方法,并查看其返回的内容。在发送哈希而不是字符串时,它应该已经返回了某种错误。

答案 1 :(得分:0)

对于任何试图使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')来引用Sendgrid动态模板ID很有用,这与在Ruby中进行硬编码(只是让我尝试使用不同的模板)而不是更改代码)。

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

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

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

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

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

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

这是my_mailer.rb中成功的红宝石代码:

  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