GitLab Pipeline通过SendGrid发送附件时遇Bad Request错误求解决
问题:GitLab Pipeline使用SendGrid发送带base64附件时返回Bad Request错误
在GitLab Pipeline中配置SendGrid发送邮件通知,发送空附件时一切正常,但附加转换为base64格式的checkov报告时,出现Bad Request错误。以下是当前的Pipeline配置:
send_email: image: alpine stage: send_email before_script: - apk add curl file script: - SENDGRID_ATTACHMENT_FILE_PATH="reports/checkov.txt" - SENDGRID_ATTACHMENT_FILENAME=$(basename $SENDGRID_ATTACHMENT_FILE_PATH) - SENDGRID_ATTACHMENT_BASE64_CONTENT=$(base64 -i $SENDGRID_ATTACHMENT_FILE_PATH) - SENDGRID_ATTACHMENT_FILETYPE=$(file -b --mime-type $SENDGRID_ATTACHMENT_FILE_PATH) - echo $SENDGRID_ATTACHMENT_FILENAME - echo $SENDGRID_ATTACHMENT_FILETYPE - echo $SENDGRID_ATTACHMENT_BASE64_CONTENT - | curl --request POST \ --url https://api.sendgrid.com/v3/mail/send \ --header "Authorization: Bearer YOUR_SENDGRID_API_KEY" \ --header "Content-Type: application/json" \ --data "{ \"personalizations\": [{\"to\": [{\"email\": \"RECIPIENT_EMAIL\"}], \"subject\": \"Your job report is here!\"}], \"content\": [{\"type\": \"text/plain\", \"value\": \"See the attached job report.\"}], \"from\": {\"email\": \"SENDER_EMAIL\", \"name\": \"Your GitLab\"}, \"attachments\": [{ \"content\": \"$SENDGRID_ATTACHMENT_BASE64_CONTENT\", \"type\": \"$SENDGRID_ATTACHMENT_FILETYPE\", \"filename\": \"$SENDGRID_ATTACHMENT_FILENAME\" }] }"
解决办法
核心问题分析
Bad Request错误主要来自两个方面:base64内容格式不符合SendGrid要求,或者手动构建的JSON存在格式问题。
1. 移除base64内容中的换行符
Alpine系统的base64命令默认会每76个字符添加换行符,而SendGrid要求附件的base64内容是无换行的单行字符串,换行符会导致JSON解析失败。
修改base64命令,添加-w 0参数禁用换行:
SENDGRID_ATTACHMENT_BASE64_CONTENT=$(base64 -i -w 0 $SENDGRID_ATTACHMENT_FILE_PATH)
2. 使用jq构建JSON避免转义问题
手动拼接JSON字符串时,若base64内容包含特殊字符(如引号),会直接破坏JSON结构。建议用jq工具来生成合法的JSON,无需手动转义。
步骤:
- 在
before_script中安装jq:apk add curl file jq - 修改script中的curl部分,用
jq构建请求体:- | curl --request POST \ --url https://api.sendgrid.com/v3/mail/send \ --header "Authorization: Bearer YOUR_SENDGRID_API_KEY" \ --header "Content-Type: application/json" \ --data "$(jq -n \ --arg to "RECIPIENT_EMAIL" \ --arg subject "Your job report is here!" \ --arg from_email "SENDER_EMAIL" \ --arg from_name "Your GitLab" \ --arg content "See the attached job report." \ --arg attach_content "$SENDGRID_ATTACHMENT_BASE64_CONTENT" \ --arg attach_type "$SENDGRID_ATTACHMENT_FILETYPE" \ --arg attach_name "$SENDGRID_ATTACHMENT_FILENAME" \ '{ personalizations: [{to: [{email: $to}], subject: $subject}], content: [{type: "text/plain", value: $content}], from: {email: $from_email, name: $from_name}, attachments: [{ content: $attach_content, type: $attach_type, filename: $attach_name }] }')"
3. 验证MIME类型(可选)
如果file命令返回的MIME类型异常(比如不是text/plain),可以手动指定类型,避免SendGrid识别错误:
SENDGRID_ATTACHMENT_FILETYPE="text/plain"
修改后的完整Pipeline配置
send_email: image: alpine stage: send_email before_script: - apk add curl file jq script: - SENDGRID_ATTACHMENT_FILE_PATH="reports/checkov.txt" - SENDGRID_ATTACHMENT_FILENAME=$(basename $SENDGRID_ATTACHMENT_FILE_PATH) - SENDGRID_ATTACHMENT_BASE64_CONTENT=$(base64 -i -w 0 $SENDGRID_ATTACHMENT_FILE_PATH) - SENDGRID_ATTACHMENT_FILETYPE=$(file -b --mime-type $SENDGRID_ATTACHMENT_FILE_PATH) - echo $SENDGRID_ATTACHMENT_FILENAME - echo $SENDGRID_ATTACHMENT_FILETYPE - echo $SENDGRID_ATTACHMENT_BASE64_CONTENT - | curl --request POST \ --url https://api.sendgrid.com/v3/mail/send \ --header "Authorization: Bearer YOUR_SENDGRID_API_KEY" \ --header "Content-Type: application/json" \ --data "$(jq -n \ --arg to "RECIPIENT_EMAIL" \ --arg subject "Your job report is here!" \ --arg from_email "SENDER_EMAIL" \ --arg from_name "Your GitLab" \ --arg content "See the attached job report." \ --arg attach_content "$SENDGRID_ATTACHMENT_BASE64_CONTENT" \ --arg attach_type "$SENDGRID_ATTACHMENT_FILETYPE" \ --arg attach_name "$SENDGRID_ATTACHMENT_FILENAME" \ '{ personalizations: [{to: [{email: $to}], subject: $subject}], content: [{type: "text/plain", value: $content}], from: {email: $from_email, name: $from_name}, attachments: [{ content: $attach_content, type: $attach_type, filename: $attach_name }] }')"
内容的提问来源于stack exchange,提问作者Shubham Aswal
相关产品推荐
相关产品推荐

