使用Golang通过电子邮件发送和读取文件的实现方法

使用Golang通过电子邮件发送和读取文件的实现方法 在使用 Golang 的 Gin REST API 时,当用户通过电子邮件输入文件,它会将文件发送给收件人,但在调试时,我遇到了这个错误。

但是当用户提交表单时,文件确实被发送了,为什么会出现文件路径错误呢?

2023/03/13 17:28:46 open C:\fakepath\deneme.pdf: 系统找不到指定的路径。 exit status 1

router.POST("/post", func(c *gin.Context) {
		// 获取表单数据
		var form forms1
		if err := c.BindJSON(&form); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid form data"})
			return
		}

		// 发送电子邮件
		auth := smtp.PlainAuth("", "xxx@gmail.com", "xxx", "smtp.gmail.com")

		to := []string{"xxx@gmail.com"}
		// 读取文件内容
		fileContent, err := ioutil.ReadFile(form.ChooseFile)
		if err != nil {
			log.Fatal(err)
		}

		// 将文件内容编码为 Base64
		encodedContent := base64.StdEncoding.EncodeToString(fileContent)

		// 将文件附加到电子邮件
		msg := []byte("To: " + strings.Join(to, ",") + "\r\n" +
			"Subject: JobApply Form Submission\r\n" +
			"MIME-version: 1.0;\r\n" +
			"Content-Type: multipart/mixed; boundary=\"boundary123\"\r\n" +
			"\r\n" +
			"--boundary123\r\n" +
			"Content-Type: text/plain; charset=utf-8\r\n" +
			"\r\n" +
			"--boundary123\r\n" +
			"Content-Type: application/octet-stream\r\n" +
			"Content-Transfer-Encoding: base64\r\n" +
			"Content-Disposition: attachment; filename=\"" + filepath.Base(form.ChooseFile) + "\"\r\n" +
			"\r\n" +
			encodedContent + "\r\n" +
			"--boundary123--")

		if err := smtp.SendMail("smtp.gmail.com:587", auth, "xxx@gmail.com", to, []byte(msg)); err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to send email"})
			return
		}

		// 发送成功响应
		c.JSON(http.StatusOK, gin.H{"status": "success"})
	})

	// 启动服务器
	if err := router.Run(":8070"); err != nil {
		panic(err)
	}
}

更多关于使用Golang通过电子邮件发送和读取文件的实现方法的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于使用Golang通过电子邮件发送和读取文件的实现方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你遇到的错误是因为 form.ChooseFile 包含的是客户端文件路径(如 C:\fakepath\deneme.pdf),这是浏览器出于安全考虑提供的假路径,服务器无法直接访问。你需要通过 Gin 的文件上传功能来获取文件内容。

以下是修正后的代码示例:

package main

import (
	"encoding/base64"
	"fmt"
	"net/http"
	"net/smtp"
	"path/filepath"
	"strings"

	"github.com/gin-gonic/gin"
)

type forms1 struct {
	// 其他表单字段
	ChooseFile string `json:"chooseFile"` // 仅用于文件名
}

func main() {
	router := gin.Default()

	router.POST("/post", func(c *gin.Context) {
		// 1. 获取上传的文件
		file, err := c.FormFile("file")
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "File upload failed"})
			return
		}

		// 2. 打开并读取文件内容
		src, err := file.Open()
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to open file"})
			return
		}
		defer src.Close()

		// 读取文件数据
		fileData := make([]byte, file.Size)
		_, err = src.Read(fileData)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to read file"})
			return
		}

		// 3. 获取其他表单数据
		var form forms1
		if err := c.ShouldBind(&form); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid form data"})
			return
		}

		// 4. 发送电子邮件
		auth := smtp.PlainAuth("", "xxx@gmail.com", "xxx", "smtp.gmail.com")
		to := []string{"xxx@gmail.com"}

		// 将文件内容编码为 Base64
		encodedContent := base64.StdEncoding.EncodeToString(fileData)

		// 构建邮件消息
		msg := []byte("To: " + strings.Join(to, ",") + "\r\n" +
			"Subject: JobApply Form Submission\r\n" +
			"MIME-version: 1.0;\r\n" +
			"Content-Type: multipart/mixed; boundary=\"boundary123\"\r\n" +
			"\r\n" +
			"--boundary123\r\n" +
			"Content-Type: text/plain; charset=utf-8\r\n" +
			"\r\n" +
			"Form submission with attached file\r\n" +
			"--boundary123\r\n" +
			"Content-Type: application/octet-stream\r\n" +
			"Content-Transfer-Encoding: base64\r\n" +
			"Content-Disposition: attachment; filename=\"" + filepath.Base(file.Filename) + "\"\r\n" +
			"\r\n" +
			encodedContent + "\r\n" +
			"--boundary123--")

		// 发送邮件
		if err := smtp.SendMail("smtp.gmail.com:587", auth, "xxx@gmail.com", to, msg); err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Failed to send email: %v", err)})
			return
		}

		// 发送成功响应
		c.JSON(http.StatusOK, gin.H{"status": "success"})
	})

	router.Run(":8070")
}

对应的 HTML 表单示例:

<form action="http://localhost:8070/post" method="post" enctype="multipart/form-data">
    <input type="file" name="file">
    <input type="text" name="chooseFile">
    <button type="submit">Submit</button>
</form>

关键修改点:

  1. 使用 c.FormFile("file") 获取上传的文件对象
  2. 通过 file.Open() 读取文件内容,而不是使用客户端提供的路径
  3. 使用 c.ShouldBind(&form) 绑定其他表单字段
  4. 直接从 file.Filename 获取文件名,而不是依赖客户端路径

这样就能正确处理文件上传并通过电子邮件发送附件了。

回到顶部