-
Notifications
You must be signed in to change notification settings - Fork 131
Closed
Labels
Description
Describe the bug
Nylas::HttpClient#build_request assumes the multipart flag will be
present under the string key "multipart":
if !payload.nil? && !payload["multipart"]
payload = payload.to_json
headers["Content-type"] = "application/json"
elsif !payload.nil? && payload["multipart"]
payload.delete("multipart")
endHowever, Nylas::FileUtils.handle_message_payload transforms all of its keys into symbols, including :multipart.
def self.handle_message_payload(request_body)
payload = request_body.transform_keys(&:to_sym)
# ...This means HttpClient incorrectly sends multipart emails as application/json, causing them to error out.
To Reproduce
Some steps involved to reproduce the bug and any code samples you can share.
# reproduce_nylas_multipart_bug.rb
# ------------------------------------------------------------
# $ ruby reproduce_nylas_multipart_bug.rb
#
# Expected: Encoding::UndefinedConversionError raised
# Source: Nylas Ruby SDK ≤ 6.4.0 (multipart symbol key not respected)
require "nylas"
require "stringio"
require "json"
# ------ 1. Fake “mailer” that builds the Nylas request body ------
class DemoNylasMailer
FORM_SIZE = 3 * 1024 * 1024 # ← keeps code identical to SDK
def initialize
@message_body = "<h1>Hello</h1>"
end
# returns the Hash we finally pass to the SDK
def request_body
attachment = large_attachment # >3 MB on purpose
body = {
body: @message_body,
from: [{name: "Alice", email: "alice@example.com"}],
to: [{email: "bob@example.com"}],
subject: "Multipart‑symbol bug",
tracking_options: {label: "demo", links: true, opens: true},
attachments: [attachment]
}
# SDK helper turns it into multipart/form‑data pieces
payload, = Nylas::FileUtils.handle_message_payload(body)
# --------------------- BUG TRIGGER -----------------------
# the helper produced payload[:multipart] **(symbol key)**
# HttpClient#build_request checks *string* "multipart",
# so it thinks this is *NOT* multipart and JSON‑encodes the Hash
# …which still contains binary values → Encoding error.
payload
end
private
def large_attachment
io = StringIO.new("A" * (FORM_SIZE + 100_000)) # 3 MB+
{ filename: "big.csv",
content_type: "text/csv",
size: io.size,
content: io }
end
end
# ------ 2. Tiny throw‑away client that only needs build_request ------
DummyClient = Class.new do
include Nylas::HttpClient
attr_accessor :api_server # HttpClient expects this ivar
end
client = DummyClient.new
client.api_server = "https://api.nylas.com" # any string is fine
# ------ 3. Execute build_request – watch it explode ---------------
mailer = DemoNylasMailer.new
payload = mailer.request_body
# THIS IS application/json BECAUSE OF THE BUG
client.send(
:build_request,
method: :post,
path: "/v3/grants/DUMMY/messages",
payload: payload,
timeout: 60,
api_key: "DUMMY_KEY"
)
Expected behavior
Multipart emails should be sent as multipart
SDK Version:
6.4.0
Additional context
The below solves the problem:
def build_request(
method:, path: nil, headers: {}, query: {}, payload: nil, timeout: nil, api_key: nil
)
url = build_url(path, query)
resulting_headers = default_headers.merge(headers).merge(auth_header(api_key))
# new line:
payload = payload.transform_keys(&:to_s) if payload.is_a?(Hash)
if !payload.nil? && !payload["multipart"]
payload = payload&.to_json
resulting_headers["Content-type"] = "application/json"
elsif !payload.nil? && payload["multipart"]
payload.delete("multipart")
end
{ method: method, url: url, payload: payload, headers: resulting_headers, timeout: timeout }
endReactions are currently unavailable