How long does a I²C message transmission take? Online calculator

Enter the number of data bytes to be transmitted (excluding the start byte containing the slave address & RW bit).

TechOverflow calculators:
You can enter values with SI suffixes like 12.2m (equivalent to 0.012) or 14k (14000) or 32u (0.000032).
The results are calculated while you type and shown directly below the calculator, so there is no need to press return or click on a Calculate button. Just make sure that all inputs are green by entering valid values.

bytes

N_{\text{bits}} = (N_{\text{bytes}} + 1) \cdot 9\Delta T_{\text{transmission}} = N_{\text{bits}} / \text{bitrate}

Posted by Uli Köhler in Calculators, Electronics

How to fix GCC lots of undefined reference to std:: functions

Problem:

When trying to compile your C++ application, you see lots of undefined reference to messages like

AutoBenchmark.cpp:(.text+0x6a): undefined reference to `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x81): undefined reference to `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x8a): undefined reference to `std::chrono::_V2::system_clock::now()'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0xcd): undefined reference to `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0xe6): undefined reference to `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()'
/usr/bin/ld: /tmp/cc356AdP.o: in function `AutoBenchmark::~AutoBenchmark()':
AutoBenchmark.cpp:(.text+0x17e): undefined reference to `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x18e): undefined reference to `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()'
/usr/bin/ld: /tmp/cc356AdP.o: in function `AutoBenchmark::Record(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)':
AutoBenchmark.cpp:(.text+0x1db): undefined reference to `std::chrono::_V2::system_clock::now()'
/usr/bin/ld: /tmp/cc356AdP.o: in function `AutoBenchmark::Record(char const*)':
AutoBenchmark.cpp:(.text+0x252): undefined reference to `std::allocator<char>::allocator()'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x288): undefined reference to `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x294): undefined reference to `std::allocator<char>::~allocator()'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x2b9): undefined reference to `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x2ce): undefined reference to `std::allocator<char>::~allocator()'
/usr/bin/ld: /tmp/cc356AdP.o: in function `AutoBenchmark::Print()':
AutoBenchmark.cpp:(.text+0x316): undefined reference to `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::length() const'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x332): undefined reference to `std::cout'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x337): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char>, std::allocator<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x344): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char)'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x572): undefined reference to `std::cout'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x577): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char>, std::allocator<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x59c): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char>, std::allocator<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x5ab): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x5c2): undefined reference to `std::ostream::operator<<(double)'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x5d1): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x607): undefined reference to `std::cout'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x60c): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char>, std::allocator<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x631): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char>, std::allocator<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x640): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x657): undefined reference to `std::ostream::operator<<(double)'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x666): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x69c): undefined reference to `std::cout'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x6a1): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char>, std::allocator<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x6c6): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char>, std::allocator<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x6d5): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x6ec): undefined reference to `std::ostream::operator<<(double)'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x6fb): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x731): undefined reference to `std::cout'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x736): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char>, std::allocator<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x75b): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char>, std::allocator<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x76a): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x781): undefined reference to `std::ostream::operator<<(double)'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x790): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
/usr/bin/ld: AutoBenchmark.cpp:(.text+0x7c6): undefined reference to `std::cout'

Solution:

You need to link the stdc++ library by adding -lstdc++ to your compiler/linker flags.

For example, instead of

gcc -o myprogram *.c

use

gcc -o myprogram *.c -lstdc++

 

Posted by Uli Köhler in C/C++, GCC errors

How to fix GCC error: expected constructor, destructor, or type conversion before __declspec(dllexport)

Problem:

When trying to compile an application on Linux, you see a compiler error message like

myheader.h:23:12: error: expected constructor, destructor, or type conversion before ‘(’ token
   23 |  __declspec(dllexport) int myfunc(

Solution:

__declspec(dllexport) is a Windows-specific feature and not available on Linux. In order to fix it in a compatible way, add this code either in a header that is included in every file containing __declspec(dllexport) or add it in each file where the error occurs:

#ifdef __linux__
#define __declspec(v)
#endif

This will basically ignore any __declspec() call on the preprocessor level.

Posted by Uli Köhler in C/C++, GCC errors

How to fix GCC undefined reference to `sqrt’

Problem:

When trying to compile your application using gcc, you see an error message like

/usr/bin/ld: /tmp/ccxPIowU.o: in function `run_mymath':
mathstuff.c:(.text+0x15d): undefined reference to `sqrt'

Solution:

You need to link the math library using the -lm flag (-lxxx means: “link the xxx library”, i.e. -lm means “link the m” library)

For example, instead of

gcc -o myprogram *.c

use

gcc -o myprogram *.c -lm

 

Posted by Uli Köhler in C/C++, GCC errors

How to fix GCC undefined reference to `_finite’ or implicit declaration of function ‘_finite’

Problem:

If you’re trying to compile Windows code on Linux, you will often see messages like

lmmin.c:261:10: warning: implicit declaration of function ‘_finite’; did you mean ‘finite’? [-Wimplicit-function-declaration]
  116 |     if(!_finite(myvalue)){

or

/usr/bin/ld: mymath.c:(.text+0x1057): undefined reference to `_finite'

and your code won’t compile.

Solution:

_finite is a function that is only available on Windows. In order to use it on Linux using GCC or G++, one option is to use isfinite() from math.h:

#include <math.h>

#define _finite(v) (isfinite((v)))

In case that function is not available (like on some Microcontroller platforms), you can use __builtin_isfinite(). Note that glibc defines isfinite() as an alias for __builtin_isfinite(). Use it like this:

#define _finite(v) (__builtin_isfinite(v))

In case you want to have code that is compatible with both platforms (Windows and Linux), use

#ifdef __linux__
#define _finite(v) (__builtin_isfinite(v))
#endif

or

#include <math.h>

#ifdef __linux__
#define _finite(v) (isfinite((v)))
#endif

 

Posted by Uli Köhler in C/C++, GCC errors

Comprehensive AWG to mm² area / mm diameter chart

This chart covers wire sizes from 0000 AWG to AWG41

AWGmm² areamm diameter
4/0 or 0000 AWG10711.68 mm
3/0 or 000 AWG8510.40384 mm
2/0 or 00 AWG67.4 mm²9.26592 mm
0 AWG53.5 mm²8.25246 mm
1 AWG42.4 mm²7.35 mm
2 AWG33.6 mm²6.54 mm
3 AWG26.7 mm²5.83 mm
4 AWG21.2 mm²5.19 mm
5 AWG16.8 mm²4.62 mm
6 AWG13.3 mm²4.11 mm
7 AWG10.6 mm²3.67 mm
8 AWG8.35 mm²3.26 mm
9 AWG6.62 mm²2.91 mm
10 AWG5.27 mm²2.59 mm
11 AWG4.15 mm²2.3 mm
12 AWG3.31 mm²2.05 mm
13 AWG2.63 mm²1.83 mm
14 AWG2.08 mm²1.63 mm
15 AWG1.65 mm²1.45 mm
16 AWG1.31 mm²1.29 mm
17 AWG1.04 mm²1.15 mm
18 AWG0.823 mm²1.024 mm
19 AWG0.653 mm²0.912 mm
20 AWG0.519 mm²0.812 mm
21 AWG0.412 mm²0.723 mm
22 AWG0.325 mm²0.644 mm
23 AWG0.259 mm²0.573 mm
24 AWG0.205 mm²0.511 mm
25 AWG0.163 mm²0.455 mm
26 AWG0.128 mm²0.405 mm
27 AWG0.102 mm²0.361 mm
28 AWG0.0804 mm²0.321 mm
29 AWG0.0646 mm²0.286 mm
30 AWG0.0503 mm²0.255 mm
31 AWG0.0404 mm²0.16002 mm
32 AWG0.0320 mm²0.2032 mm
33 AWG0.0254 mm²0.18034 mm
34 AWG0.0201 mm²0.16002 mm
35 AWG0.0160 mm²0.14224 mm
36 AWG0.0127 mm²0.12700 mm
37 AWG0.0100 mm²0.11430 mm
38 AWG0.00797 mm²0.10160 mm
39 AWG0.00632 mm²0.08890 mm
40 AWG0.00501 mm²0.07874 mm
Posted by Uli Köhler in Electronics

What are typical insertion & withdrawal forces for PCIe connectors?

This Amphenol datasheet lists 1.15 N/pin insertion force and 0.15 N/pin withdrawal force.

Based on these values:

  • A PCIe x1 connector with 36 pins
    • insertion force of 36*1.15N = 41.4 N = 4.22 kgf and
    • withdrawal force of 36*0.15N = 5.4 N = 0.551 kgf
  • A PCIe x4 connector with 64 pins
    • insertion force of 64*1.15N = 73.6 N = 7.505 kgf and
    • withdrawal force of 64*0.15N = 9.6 N = 0.979 kgf
  • A PCIe x8 connector with 98 pins
    • insertion force of 98*1.15N = 112.7 N = 11.492 kgf and
    • withdrawal force of 98*0.15N = 14.7 N = 1.499 kgf
  • A PCIe x16 connector with 164 pins
    • insertion force of 164*1.15N = 188.6 N = 19.232 kgf and
    • withdrawal force of 164*0.15N = 24.6 N = 2.509 kgf
  • A PCIe x24 connector with 230 pins
    • insertion force of 230*1.15N = 264.5 N = 4.22 kgf and
    • withdrawal force of 230*0.15N = 34.5 N = 3.518 kgf
Posted by Uli Köhler in Electronics

How many pins does a PCIe connector have?

A PCIe x1 connector has 36 pins (18 pins on each side)

A PCIe x4 connector has 64 pins (32 pins on each side)

A PCIe x8 connector has 98 pins (49 pins on each side)

A PCIe x16 connector has 164 pins (82 pins on each side)

A PCIe x24 connector has 230 pins (115 pins on each side)

Source: Samtec catalog, Amphenol datasheet (x24)

 

Posted by Uli Köhler in Electronics

How to ignore pylint problem for a specific single line of code

If you have a Python line of code like

writer = pd.ExcelWriter(filename)

that produces a pylint problem message like

Abstract class 'ExcelWriter' with abstract methods instantiated pylint(abstract-class-instantiated)

you can ignore it by adding a comment in the format # pylint: disable=[problem-code] at the end of the line where [problem-code] is the value inside pylint(...) in the pylint message – for example, abstract-class-instantiated for the problem report listed above.

The modified line will look like this:

writer = pd.ExcelWriter(filename) # pylint: disable=abstract-class-instantiated

You can also add the comment line

# pylint: disable=abstract-class-instantiated

to the function-level (or to any other block-level) to disable that pylint rule for the entire current function or block.

Posted by Uli Köhler in Python

How to migrate from ansicolor to ansicolors

The ansicolor package in Python has not been updated in a long time and doesn’t have any documentation on PyPI. Therfore, I migrated my Python scripts to ansicolors (with an s at the end). Only a few steps are neccessary:

First, replace

from ansicolor import red

by

from colors import red

Additionally, bold=True is called style="bold" in ansicolors, hence you need to replace

red("msg", bold=True)

by

red("msg", style="bold")
Posted by Uli Köhler in Python

How to fix matplotlib .ylabel() AttributeError: ‘AxesSubplot’ object has no attribute ‘ylabel’

Problem:

You want to set the ylabel of a matplotlib plot using .ylabel("My ylabel") but you see an error messsage like

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-12-28a87d95bccc> in <module>
---> 11 axs[0].ylabel("My ylabel")

AttributeError: 'AxesSubplot' object has no attribute 'ylabel'

Solution:

Use .set_ylabel("My ylabel") instead of .ylabel("My ylabel") !

While

from matplotlib import pyplot as plt

plt.ylabel("My ylabel")

works fine, if you have an axes object like the one you get from plt.subplots(), you’ll have to use set_ylabel()!

from matplotlib import pyplot as plt
fig, axs = plt.subplots(2, 1)
# ...
axs[0].set_ylabel("My ylabel")

 

Posted by Uli Köhler in Python

How to fix matplotlib .xlabel() AttributeError: ‘AxesSubplot’ object has no attribute ‘xlabel’

Problem:

You want to set the xlabel of a matplotlib plot using .xlabel("My xlabel") but you see an error messsage like

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-12-28a87d95bccc> in <module>
---> 11 axs[0].xlabel("My xlabel")

AttributeError: 'AxesSubplot' object has no attribute 'xlabel'

Solution:

Use .set_xlabel("My xlabel") instead of .xlabel("My xlabel") !

While

from matplotlib import pyplot as plt

plt.xlabel("My xlabel")

works fine, if you have an axes object like the one you get from plt.subplots(), you’ll have to use set_xlabel()!

from matplotlib import pyplot as plt
fig, axs = plt.subplots(2, 1)
# ...
axs[0].set_xlabel("My xlabel")

 

Posted by Uli Köhler in Python

How to fix matplotlib .title() TypeError: ‘Text’ object is not callable

Problem:

You want to set the title of a matplotlib plot using .title("My title") but you see an error messsage like

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-11-f5f930f00eac> in <module>
---> 10 axs[0].title("My title")

TypeError: 'Text' object is not callable

Solution:

Use .set_title("My title") instead of .title("My title") !

While

from matplotlib import pyplot as plt

plt.title("My title")

works fine, if you have an axes object like the one you get from plt.subplots(), you’ll have to use set_title()!

from matplotlib import pyplot as plt
fig, axs = plt.subplots(2, 1)
# ...
axs[0].set_title("My title")

 

Posted by Uli Köhler in Python

How to replace string in column names in Pandas DataFrame

Use this snippet in order to replace a string in column names for a pandas DataFrame:

new_df = df.rename(lambda s: s.replace("A", "B")) # df will not be modified !

You can also modify the column names in-place (i.e. modify the original DataFrame):

df.rename(lambda s: s.replace("A", "B"), inplace=True)

For example, if you have the columns ["ColumnA", "X", "Y"] before running .rename(), the result will have ["ColumnB", "X", "Y"] (the "A" has been replaced by "B")

Posted by Uli Köhler in pandas, Python

How to find out if BytesIO is empty in Python

In order to find out if a BytesIO instance is empty or not, get its size and then check if it’s > 0:

my_bytesio.getbuffer().nbytes > 0

The following example shows how to use it in an if clause:

if my_bytesio.getbuffer().nbytes > 0:
    print("my_bytesio is empty")
else:
    print("my_bytesio is NOT empty")

 

Posted by Uli Köhler in Python

How to fix Synology Docker: failed to initialize logging driver: database is locked

Problem:

When you try to start a specific Docker container using the Synology NAS GUI, the container is being stopped unexpectedly and you see an error message like this in the logs:

Start container mycontainer failed: {"message":"failed to initialize logging driver: database is locked"}.
Signal container mycontainer failed: {"message":"Cannot kill container: mycontainer: Container 5136ddceeb46004c5b18f04eb9ec10cac3808938515874fc31185b0964232201 is not running"}.

Solution:

I fixed this problem by stopping the container, duplicating the container session: Right click on the container -> Settings -> Duplicate Settings

That will create a new container with the given settings. Note that local ports will be set to Auto and will not be copied over, so if you use fixed local ports, you need to set them to a different value in the original container and then set the local ports on the new container to the desired fixed value. Also note that files inside the container are not copied over. In my configuration, all relevant files are stored in mapped volumes on the NAS.

The root cause of this issue seems to be that the logging database for this specific container has been locked by some process. The issue is always limited to a certain container and will not affect other containers (though it could in principle occur for more than one container). I know that at least in my specific case, the issue is not caused by a reboot and will also not be fixed by a reboot of the Synology NAS. Just before I encountered the issue, my NAS had not been rebooted for months, but it might be related to Synology package updates since I updated some packages using the Package manager just before encountering the issue, including a Synology Mail Plus update which failed on the first attempt, but succeeded when I clicked Update again.

Posted by Uli Köhler in Docker, Networking

How to send email with BytesIO attachment via SMTP in Python

This example details how to send an email in Python, with an attachment from a io.BytesIO instance instead of reading the attachment from a file on the filesystem:

#!/usr/bin/env python3
__author__ = "Uli Köhler"
__license__ = "CC0 1.0 Universal (public domain)"
__version__ = "1.0"
import smtplib
import mimetypes
from io import BytesIO
from email.message import EmailMessage

# Create message and set text content
msg = EmailMessage()
msg['Subject'] = 'This email contains an attachment'
msg['From'] = '[email protected]'
msg['To'] = '[email protected]'
# Set text content
msg.set_content('Please see attached file')

def attach_bytesio_to_email(email, buf, filename):
    """Attach a file identified by filename, to an email message"""
    # Reset read position & extract data
    buf.seek(0)
    binary_data = buf.read()
    # Guess MIME type or use 'application/octet-stream'
    maintype, _, subtype = (mimetypes.guess_type(filename)[0] or 'application/octet-stream').partition("/")
    # Add as attachment
    email.add_attachment(binary_data, maintype=maintype, subtype=subtype, filename=filename)

# Attach files
buf = BytesIO()
buf.write(b"This is a test text")
attach_bytesio_to_email(msg, buf, "test.txt")

def send_mail_smtp(mail, host, username, password):
    s = smtplib.SMTP(host)
    s.starttls()
    s.login(username, password)
    s.send_message(msg)
    s.quit()

send_mail_smtp(msg, 'smtp.my-domain.com', '[email protected]', 'sae7ooka0S')

The script from above is using the following utility functions:

def attach_bytesio_to_email(email, buf, filename):
    """Attach a file identified by filename, to an email message"""
    # Reset read position &amp; extract data
    buf.seek(0)
    binary_data = buf.read()
    # Guess MIME type or use 'application/octet-stream'
    maintype, _, subtype = (mimetypes.guess_type(filename)[0] or 'application/octet-stream').partition("/")
    # Add as attachment
    email.add_attachment(binary_data, maintype=maintype, subtype=subtype, filename=filename

def send_mail_smtp(mail, host, username, password):
    s = smtplib.SMTP(host)
    s.starttls()
    s.login(username, password)
    s.send_message(msg)
    s.quit()

which you can use in your code directly. The easiest way to initialize the email message is using

# Create message and set text content
msg = EmailMessage()
msg['Subject'] = 'This email contains an attachment'
msg['From'] = '[email protected]'
msg['To'] = '[email protected]'
# Set text content
msg.set_content('Please see attached file')

and then attaching your BytesIO instance (named buf) using

attach_bytesio_to_email(msg, buf, "test.txt")

and once you’re finished with adding attachments, sending the message using

send_mail_smtp(msg, 'smtp.my-domain.com', '[email protected]', 'sae7ooka0S')

 

Posted by Uli Köhler in E-Mail, Python

How to send email with file attachment via SMTP in Python

This example shows how to send an email with an attachment in Python, with the attachment being read from a file from the filesystem:

#!/usr/bin/env python3
import smtplib
import mimetypes
from email.message import EmailMessage

# Create message and set text content
msg = EmailMessage()
msg['Subject'] = 'This email contains an attachment'
msg['From'] = '[email protected]'
msg['To'] = '[email protected]'
# Set text content
msg.set_content('Please see attached file')

def attach_file_to_email(email, filename):
    """Attach a file identified by filename, to an email message"""
    with open(filename, 'rb') as fp:
        file_data = fp.read()
        maintype, _, subtype = (mimetypes.guess_type(filename)[0] or 'application/octet-stream').partition("/")
        email.add_attachment(file_data, maintype=maintype, subtype=subtype, filename=filename)

# Attach files
attach_file_to_email(msg, "myfile.pdf")

def send_mail_smtp(mail, host, username, password):
    s = smtplib.SMTP(host)
    s.starttls()
    s.login(username, password)
    s.send_message(msg)
    s.quit()

send_mail_smtp(msg, 'smtp.my-domain.com', '[email protected]', 'sae7ooka0S')

The utility functions in this code are:

import smtplib
import mimetypes

def attach_file_to_email(email, filename):
    """Attach a file identified by filename, to an email message"""
    with open(filename, 'rb') as fp:
        file_data = fp.read()
        maintype, _, subtype = (mimetypes.guess_type(filename)[0] or 'application/octet-stream').partition("/")
        email.add_attachment(file_data, maintype=maintype, subtype=subtype, filename=filename)

def send_mail_smtp(mail, host, username, password):
    s = smtplib.SMTP(host)
    s.starttls()
    s.login(username, password)
    s.send_message(msg)
    s.quit()

Initialize your email like this:

# Create message and set text content
msg = EmailMessage()
msg['Subject'] = 'This email contains an attachment'
msg['From'] = '[email protected]'
msg['To'] = '[email protected]'
# Set text content
msg.set_content('Please see attached file')

and then attach the file like this:

attach_file_to_email(msg, "myfile.pdf")

and send the email using

send_mail_smtp(msg, 'smtp.my-domain.com', '[email protected]', 'sae7ooka0S')
Posted by Uli Köhler in Python