How to send an email with attachments using an SDK

更新时间:
复制 MD 格式

Send emails with file attachments by using the Alibaba Cloud DirectMail SDK. Code samples are provided in Python, Java, PHP, and Go.

Note

The total size of an email with attachments cannot exceed 15 MB. An email can contain a maximum of 100 attachments.

The 15 MB limit applies to the total size of the sent email, which includes the email header, email body, and attachments. Because Base64 encoding increases the file size, the final email can be more than 1.5 times the size of the original attachments. Therefore, keep the total size of your original attachment files to 8 MB or less. To send larger files, add hyperlinks to them in the email body.

# -*- coding: utf-8 -*-
import sys
from typing import List
from typing import BinaryIO
from alibabacloud_dm20151123.client import Client as Dm20151123Client
from alibabacloud_tea_openapi import models as open_api_models
from alibabacloud_dm20151123 import models as dm_20151123_models
from alibabacloud_tea_util import models as util_models
from alibabacloud_dm20151123 import models as main_models

attachments = []


class Sample:
    def __init__(self) -> None:
        pass

    @staticmethod
    def create_client() -> Dm20151123Client:
        """
        Initializes a client with credentials.
        @return: Client
        @throws Exception
        """
        # For production code, we recommend using a more secure method that does not require an AccessKey pair. For more information about credential configuration, see https://help.aliyun.com/document_detail/378659.html.
        config = open_api_models.Config(
            access_key_id='xxxxxx',
            access_key_secret='xxxxxx'
        )
        # For more information about endpoints, see https://api.aliyun.com/product/Dm
        config.endpoint = f'dm.aliyuncs.com'
        config.region_id = f'cn-hangzhou'
        return Dm20151123Client(config)

    @staticmethod
    def main(
            args: List[str],
    ) -> None:
        client = Sample.create_client()
        single_sendmail_request = dm_20151123_models.SingleSendMailAdvanceRequest(
            account_name='sender@example.com',
            address_type='1',
            reply_to_address='true',
            to_address='recipient@example.com',
            subject='Subject',
            html_body='Email body',
            attachments=getAttachments()
        )
        try:
            # When you copy the code to run, print the API return value.
            response = client.single_send_mail_advance(single_sendmail_request, util_models.RuntimeOptions())
            print(response)
        except Exception as error:
            # This is for demonstration purposes only. Handle exceptions with care. Do not ignore exceptions in your project.
            # Error message
            print(error.data)
            # # Diagnosis address
            # print(error.data.get("Recommend"))
            # UtilClient.assert_as_string(error.message)

def getAttachments() -> List[main_models.SingleSendMailAdvanceRequestAttachments]:
    attach = main_models.SingleSendMailAdvanceRequestAttachments("test1.txt", getFile(r"C:\Users\Downloads\111.txt"))
    attach1 = main_models.SingleSendMailAdvanceRequestAttachments("test2.txt", getFile(r"C:\Users\Downloads\222.txt"))
    attachments.append(attach)
    attachments.append(attach1)
    return attachments


def getFile(v_file) -> BinaryIO:
    f = open(v_file, 'rb')
    return f


if __name__ == '__main__':
    Sample.main(sys.argv[1:])
package org.example;

import com.aliyun.dm20151123.models.SingleSendMailAdvanceRequest;
import com.aliyun.dm20151123.models.SingleSendMailResponse;
import com.aliyun.tea.TeaException;
import com.google.gson.Gson;

import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.List;

public class Sample {
    /**
     * description :
     * <p>Initializes a client with credentials.</p>
     * @return Client
     *
     * @throws Exception
     */
    public static com.aliyun.dm20151123.Client createClient() throws Exception {
        // For production code, we recommend using a more secure method that does not require an AccessKey pair. For more information about credential configuration, see https://help.aliyun.com/document_detail/378657.html.
//        com.aliyun.credentials.Client credential = new com.aliyun.credentials.Client();
        com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
                .setAccessKeyId("xxxxxx")
                .setAccessKeySecret("xxxxxx");
        // For more information about endpoints, see https://api.aliyun.com/product/Dm
        config.endpoint = "dm.aliyuncs.com";
        config.regionId = "cn-hangzhou";
        return new com.aliyun.dm20151123.Client(config);
    }
    private static final Gson gson = new Gson(); // Add a Gson instance
    public static void main(String[] args_) throws Exception {


        com.aliyun.dm20151123.Client client = Sample.createClient();
        SingleSendMailAdvanceRequest singleSendMailAdvanceRequest = new SingleSendMailAdvanceRequest();
        List<SingleSendMailAdvanceRequest.SingleSendMailAdvanceRequestAttachments> attachments = new ArrayList<>();
        SingleSendMailAdvanceRequest.SingleSendMailAdvanceRequestAttachments attachment1 = new SingleSendMailAdvanceRequest.SingleSendMailAdvanceRequestAttachments();
        attachment1.setAttachmentName("test1.txt");
        attachment1.setAttachmentUrlObject(new FileInputStream(new File("C:\\Users\\Downloads\\111.txt")));


        SingleSendMailAdvanceRequest.SingleSendMailAdvanceRequestAttachments attachment2 = new SingleSendMailAdvanceRequest.SingleSendMailAdvanceRequestAttachments();
        attachment2.setAttachmentName("test2.txt");
        attachment2.setAttachmentUrlObject(new FileInputStream(new File("C:\\Users\\Downloads\\222.txt")));
        attachments.add(attachment1);
        attachments.add(attachment2);
        singleSendMailAdvanceRequest.setAttachments(attachments);

        singleSendMailAdvanceRequest.setAccountName("sender@example.com");
        singleSendMailAdvanceRequest.setAddressType(1);
        singleSendMailAdvanceRequest.setReplyToAddress(true);
        singleSendMailAdvanceRequest.setToAddress("recipient@example.com");
        singleSendMailAdvanceRequest.setSubject("Subject");
        singleSendMailAdvanceRequest.setHtmlBody("Email body");
        singleSendMailAdvanceRequest.setClickTrace("1");


        try {
            // When you copy the code to run, print the API return value.
            SingleSendMailResponse response =  client.singleSendMailAdvance(singleSendMailAdvanceRequest, new com.aliyun.teautil.models.RuntimeOptions());

            System.out.println(gson.toJson(response));
        } catch (TeaException error) {
            // This is for demonstration purposes only. Handle exceptions with care. Do not ignore exceptions in your project.
            // Error message
            System.out.println(error.getMessage());
            // Diagnosis address
            System.out.println(error.getData().get("Recommend"));
            com.aliyun.teautil.Common.assertAsString(error.message);
        } catch (Exception _error) {
            TeaException error = new TeaException(_error.getMessage(), _error);
            // This is for demonstration purposes only. Handle exceptions with care. Do not ignore exceptions in your project.
            // Error message
            System.out.println(error.getMessage());
            // Diagnosis address
            System.out.println(error.getData().get("Recommend"));
            com.aliyun.teautil.Common.assertAsString(error.message);
        }
    }
}

<?php

// This file is auto-generated, don't edit it. Thanks.
namespace AlibabaCloud\SDK\Sample;

use AlibabaCloud\SDK\Dm\V20151123\Dm;
// use AlibabaCloud\Credentials\Credential;
use \Exception;
use AlibabaCloud\Tea\Exception\TeaError;
use AlibabaCloud\Tea\Utils\Utils;

use Darabonba\OpenApi\Models\Config;
use AlibabaCloud\SDK\Dm\V20151123\Models\SingleSendMailAdvanceRequest;
use AlibabaCloud\SDK\Dm\V20151123\Models\SingleSendMailAdvanceRequest\attachments;
use GuzzleHttp\Psr7\Stream;
use AlibabaCloud\Tea\Utils\Utils\RuntimeOptions;

require_once __DIR__ . '\\..\\..\\vendor\\autoload.php';

class Sample {

    /**
     * Initializes a client with credentials.
     * @return Dm Client
     */
    public static function createClient(){
        // For production code, we recommend using a more secure method that does not require an AccessKey pair. For more information about credential configuration, see https://help.aliyun.com/document_detail/311677.html.
        $config = new Config([
            "accessKeyId" => "xxxxxx",
            "accessKeySecret" => "xxxxxxx"
        ]);
        // For more information about endpoints, see https://api.aliyun.com/product/Dm
        $config->endpoint = "dm.aliyuncs.com";        
        $config->regionId = "cn-hangzhou";        
        return new Dm($config);
    }
    // public static function createClient(){
    //     // For production code, we recommend using a more secure method that does not require an AccessKey pair. For more information about credential configuration, see https://help.aliyun.com/document_detail/311677.html.
    //     $credential = new Credential();
    //     $config = new Config([
    //         "credential" => $credential
    //     ]);
    //     // For more information about endpoints, see https://api.aliyun.com/product/Dm
    //     $config->endpoint = "dm.aliyuncs.com";
    //     $config->regionId = "cn-hangzhou";
    //     return new Dm($config);
    // }
    /**
     * Gets the file stream.
     * @param string $filePath File path
     * @return Stream
     */
    public static function getFile($filePath) {
        $fileResource = fopen($filePath, 'rb');
        $fileSize = filesize($filePath); // Get the file size
        var_dump("File size:");
        var_dump($fileSize);
        return new Stream($fileResource);
    }

    /**
     * Gets the attachment list.
     * @return array
     */
    public static function getAttachments() {
        $attachments = [];
        
        // Create the first attachment
        $attachment1 = new attachments();
        $attachment1->attachmentName = "test1.txt";
        $attachment1->attachmentUrlObject = self::getFile("C:\\Users\\Downloads\\111.txt");
        $attachments[] = $attachment1;
        
        // Create the second attachment
        $attachment2 = new attachments();
        $attachment2->attachmentName = "test2.txt";
        $attachment2->attachmentUrlObject = self::getFile("C:\\Users\\Downloads\\222.txt");
        $attachments[] = $attachment2;
        //print $attachments;
        var_dump($attachments);
        return $attachments;
    }

    /**
     * @param string[] $args
     * @return void
     */
    public static function main($args){
        $client = self::createClient();
        
        // Create the email request
        $singleSendMailRequest = new SingleSendMailAdvanceRequest([
            "accountName" => "sender@example.com",
            "addressType" => 1,
            "replyToAddress" => true,
            "subject" => "Subject",
            "toAddress" => "recipient@example.com",            
            "attachments" => self::getAttachments(),
            "htmlBody" => "<h1>Content</h1>",
            "textBody" => "Content"
        ]);
        
        // // Create runtime options
        // $runtime = new RuntimeOptions([
        //     "ca" => "C:\\Users\\cacert.pem" // Specify the local CA certificate path
        // ]);
        $runtime = new RuntimeOptions();
        
        try {
            // Send the email
            $client->singleSendMailAdvance($singleSendMailRequest, $runtime);
            var_dump("Sent successfully");
        }
        catch (Exception $error) {
            if (!($error instanceof TeaError)) {
                $error = new TeaError([], $error->getMessage(), $error->getCode(), $error);
            }
            // This is for demonstration purposes only. Handle exceptions with care. Do not ignore exceptions in your project.
            // Error message
            var_dump($error->message);
            // Diagnosis address
            var_dump($error->data["Recommend"]);
            Utils::assertAsString($error->message);
        }
    }
}
$path = __DIR__ . \DIRECTORY_SEPARATOR . '..' . \DIRECTORY_SEPARATOR . 'vendor' . \DIRECTORY_SEPARATOR . 'autoload.php';
if (file_exists($path)) {
    require_once $path;
}
Sample::main(array_slice($argv, 1));
package main

import (
	"fmt"
	"os"

	openapiutil "github.com/alibabacloud-go/darabonba-openapi/v2/utils"
	dm "github.com/alibabacloud-go/dm-20151123/v2/client"
	"github.com/alibabacloud-go/tea/dara"
	"github.com/aliyun/credentials-go/credentials"
)

// Description:
//
// Initializes a client with credentials.
//
// @return Client
//
// @throws Exception
func CreateClient() (_result *dm.Client, _err error) {
	config := new(credentials.Config).
		SetType("access_key").
		SetAccessKeyId("xxxxxx").
		SetAccessKeySecret("xxxxxx")

	akCredential, err := credentials.NewCredential(config)
	if err != nil {
		return _result, err
	}

	openapiConfig := &openapiutil.Config{
		Credential: akCredential,
	}
	// For more information about endpoints, see https://api.aliyun.com/product/Dm
	openapiConfig.Endpoint = dara.String("dm.aliyuncs.com")
	_result, _err = dm.NewClient(openapiConfig)
	return _result, _err
}

func main() {
	err := _main(dara.StringSlice(os.Args[1:]))
	if err != nil {
		panic(err)
	}
}

func _main(args []*string) (_err error) {
	client, _err := CreateClient()
	if _err != nil {
		return _err
	}

	// Create attachments
	attachments, _err := getAttachments()
	if _err != nil {
		return _err
	}

	// Use SingleSendMailAdvanceRequest instead of SingleSendMailRequest
	singleSendMailRequest := &dm.SingleSendMailAdvanceRequest{
		AccountName:    dara.String("sender@example.com"),
		AddressType:    dara.Int32(1),
		ReplyToAddress: dara.Bool(true),
		ToAddress:      dara.String("recipient@example.com"),
		Subject:        dara.String("Subject"),
		HtmlBody:       dara.String("Email body"),
		Attachments:    attachments,
	}

	runtime := &dara.RuntimeOptions{}
	// Use the SingleSendMailAdvance method instead of SingleSendMailWithOptions
	resp, _err := client.SingleSendMailAdvance(singleSendMailRequest, runtime)
	if _err != nil {
		fmt.Printf("[ERROR] %s\n", _err.Error())
		return _err
	}

	fmt.Printf("[LOG] %s\n", dara.Stringify(resp))
	return _err
}

// getAttachments gets the attachment list
func getAttachments() ([]*dm.SingleSendMailAdvanceRequestAttachments, error) {
	// Note: You need to change the file path to your actual file path.
	attach1, err := createAttachmentFromFile("test1.txt", `C:\Users\Downloads\111.txt`)
	if err != nil {
		return nil, fmt.Errorf("Failed to create attachment test1.txt: %v", err)
	}

	attach2, err := createAttachmentFromFile("test2.txt", `C:\Users\Downloads\222.txt`)
	if err != nil {
		return nil, fmt.Errorf("Failed to create attachment test2.txt: %v", err)
	}

	return []*dm.SingleSendMailAdvanceRequestAttachments{attach1, attach2}, nil
}

// createAttachmentFromFile creates an attachment from a file
func createAttachmentFromFile(name, filePath string) (*dm.SingleSendMailAdvanceRequestAttachments, error) {
	// Open the file
	file, err := os.Open(filePath)
	if err != nil {
		return nil, fmt.Errorf("Cannot open file %s: %v", filePath, err)
	}

	// Get file information
	fileInfo, err := file.Stat()
	if err != nil {
		file.Close()
		return nil, fmt.Errorf("Cannot get file information for %s: %v", filePath, err)
	}

	// Check the file size
	// if fileInfo.Size() > 15*1024*1024 {
	// 	file.Close()
	// 	return nil, fmt.Errorf("File %s exceeds the size limit", filePath)
	// }

	// Create an attachment object and use the file as an io.Reader
	attachment := &dm.SingleSendMailAdvanceRequestAttachments{
		AttachmentName:      dara.String(name),
		AttachmentUrlObject: file, // Use the file directly as an io.Reader
	}

	fmt.Printf("Successfully created attachment %s, size: %d bytes\n", name, fileInfo.Size())

	// Note: In a real application, you may need to keep the file open until the sending is complete
	// or read the file content into memory to avoid file handle issues

	return attachment, nil
}
Note

Download the latest SDK package from OpenAPI Explorer to access the attachment-related methods.

If you are using a VPC server and require an internal network connection, set the config.setEndpointType("internal"); parameter.

API call description (Examples are not yet available for all programming languages, but the basic logic is similar)

The following example uses Python:

The basic logic is to read each file as a binary stream, add the attachments to a list, and pass the list to the attachment field. Then, call the single_send_mail_advance operation to send the email. This operation replaces singleSendMailWithOptions.

  • SingleSendMailAdvanceRequestAttachments

Defines an email attachment, including the file name and content as a binary stream.

  • SingleSendMailAdvanceRequest

Encapsulates all parameters required to send an email, including the sender, recipient, subject, body, and attachments.

  • single_send_mail_advance: Sends an email.

Call this method on a Dm20151123Client instance to send an email with attachments.

Result

image

You can use the troubleshooting tool to query the request ID and verify that the parameters are passed correctly.

image

Error message: code: 400, The attachment url is invalid

Verify that the attachment path and region values are correct. Also, ensure that you have switched to a method that supports attachments. For example, in Python, you must use single_send_mail_advance instead of single_send_mail_with_options.

config.endpoint = "dm.aliyuncs.com";

config.regionId = "cn-hangzhou";

Note

Replace the endpoint and region ID with the values for your region.

Error when uploading attachments using the Java example: NoSuchFieldError: _key

image

Version 1.8.1 of dm20151123 requires a later version of tea-openapi. To resolve this issue, update tea-openapi to version 0.3.10 or later:

<dependency>
      <groupId>com.aliyun</groupId>
      <artifactId>dm20151123</artifactId>            
      <version>1.8.1</version>
</dependency>
<dependency>
      <groupId>com.aliyun</groupId>
      <artifactId>tea-openapi</artifactId>
      <version>0.3.10</version>
</dependency>