With tcolorbox:
\documentclass{article} \usepackage[many]{tcolorbox} \usepackage{xcolor} \usepackage{varwidth} \usepackage{environ} \usepackage{xparse} \newlength{\bubblewidth} \AtBeginDocument{\setlength{\bubblewidth}{.75\textwidth}} \definecolor{bubblegreen}{RGB}{103,184,104} \definecolor{bubblegray}{RGB}{241,240,240} \newcommand{\bubble}[4]{% \tcbox[ colback=#1, colframe=#1, #2, ]{\color{#3}\begin{varwidth}{\bubblewidth}#4\end{varwidth}}% } \ExplSyntaxOn \seq_new:N \l__ooker_bubbles_seq \tl_new:N \l__ooker_bubbles_first_tl \tl_new:N \l__ooker_bubbles_last_tl \NewEnviron{rightbubbles} { \raggedleft\sffamily \seq_set_split:NnV \l__ooker_bubbles_seq { \par } \BODY \int_compare:nTF { \seq_count:N \l__ooker_bubbles_seq < 2 } { \bubble{bubblegreen}{rounded~corners}{white}{\BODY} } { \seq_pop_left:NN \l__ooker_bubbles_seq \l__ooker_bubbles_first_tl \seq_pop_right:NN \l__ooker_bubbles_seq \l__ooker_bubbles_last_tl \bubble{bubblegreen}{sharp~corners=southeast}{white}{\l__ooker_bubbles_first_tl}\par \seq_map_inline:Nn \l__ooker_bubbles_seq { \bubble{bubblegreen}{sharp~corners=east}{white}{##1}\par } \bubble{bubblegreen}{sharp~corners=northeast}{white}{\l__ooker_bubbles_last_tl}\par } } \NewEnviron{leftbubbles} { \raggedright\sffamily \seq_set_split:NnV \l__ooker_bubbles_seq { \par } \BODY \int_compare:nTF { \seq_count:N \l__ooker_bubbles_seq < 2 } { \bubble{bubblegray}{rounded~corners}{black}{\BODY} } { \seq_pop_left:NN \l__ooker_bubbles_seq \l__ooker_bubbles_first_tl \seq_pop_right:NN \l__ooker_bubbles_seq \l__ooker_bubbles_last_tl \bubble{bubblegray}{sharp~corners=southwest}{black}{\l__ooker_bubbles_first_tl}\par \seq_map_inline:Nn \l__ooker_bubbles_seq { \bubble{bubblegray}{sharp~corners=west}{black}{##1}\par } \bubble{bubblegray}{sharp~corners=northwest}{black}{\l__ooker_bubbles_last_tl}\par } } \ExplSyntaxOff \begin{document} \begin{rightbubbles} Left-aligned gray bubbles (241, 240, 240) with black text Right-aligned green bubbles (103, 184,104) with white text Bubbles only break after a paragraph (equivalent to an enter press when chatting). Long message with multiple lines will be kept in one bubble. Left and right edges are round. \end{rightbubbles} \begin{leftbubbles} Left-aligned gray bubbles (241, 240, 240) with black text Right-aligned green bubbles (103, 184,104) with white text Bubbles only break after a paragraph (equivalent to an enter press when chatting). Long message with multiple lines will be kept in one bubble. Left and right edges are round. \end{leftbubbles} \begin{rightbubbles} Single \end{rightbubbles} \begin{leftbubbles} End \end{leftbubbles} \end{document}

If I change the definition of \bubble to
\newcommand{\bubble}[4]{% \tcbox[ arc=5mm, colback=#1, colframe=#1, #2, ]{\color{#3}\begin{varwidth}{\bubblewidth}#4\end{varwidth}}% }
then the output is as follows:

Improved version
You can define the spacing between bubbles by setting \bubblesep. Different color bubbles are enclosed in flushleft and flushright environments, so there will be \topsep space between them.
\documentclass{article} \usepackage[many]{tcolorbox} \usepackage{xcolor} \usepackage{varwidth} \usepackage{environ} \usepackage{xparse} \newlength{\bubblesep} \newlength{\bubblewidth} \setlength{\bubblesep}{2pt} \AtBeginDocument{\setlength{\bubblewidth}{.75\textwidth}} \definecolor{bubblegreen}{RGB}{103,184,104} \definecolor{bubblegray}{RGB}{241,240,240} \newcommand{\bubble}[4]{% \tcbox[ on line, arc=4.5mm, colback=#1, colframe=#1, #2, ]{\color{#3}\begin{varwidth}{\bubblewidth}#4\end{varwidth}}% } \ExplSyntaxOn \seq_new:N \l__ooker_bubbles_seq \tl_new:N \l__ooker_bubbles_first_tl \tl_new:N \l__ooker_bubbles_last_tl \NewEnviron{rightbubbles} { \begin{flushright} \sffamily \seq_set_split:NnV \l__ooker_bubbles_seq { \par } \BODY \int_compare:nTF { \seq_count:N \l__ooker_bubbles_seq < 2 } { \bubble{bubblegreen}{rounded~corners}{white}{\BODY}\par } { \seq_pop_left:NN \l__ooker_bubbles_seq \l__ooker_bubbles_first_tl \seq_pop_right:NN \l__ooker_bubbles_seq \l__ooker_bubbles_last_tl \bubble{bubblegreen}{sharp~corners=southeast}{white}{\l__ooker_bubbles_first_tl} \par\nointerlineskip \addvspace{\bubblesep} \seq_map_inline:Nn \l__ooker_bubbles_seq { \bubble{bubblegreen}{sharp~corners=east}{white}{##1} \par\nointerlineskip \addvspace{\bubblesep} } \bubble{bubblegreen}{sharp~corners=northeast}{white}{\l__ooker_bubbles_last_tl} \par } \end{flushright} } \NewEnviron{leftbubbles} { \begin{flushleft} \sffamily \seq_set_split:NnV \l__ooker_bubbles_seq { \par } \BODY \int_compare:nTF { \seq_count:N \l__ooker_bubbles_seq < 2 } { \bubble{bubblegray}{rounded~corners}{black}{\BODY}\par } { \seq_pop_left:NN \l__ooker_bubbles_seq \l__ooker_bubbles_first_tl \seq_pop_right:NN \l__ooker_bubbles_seq \l__ooker_bubbles_last_tl \bubble{bubblegray}{sharp~corners=southwest}{black}{\l__ooker_bubbles_first_tl} \par\nointerlineskip \addvspace{\bubblesep} \seq_map_inline:Nn \l__ooker_bubbles_seq { \bubble{bubblegray}{sharp~corners=west}{black}{##1} \par\nointerlineskip \addvspace{\bubblesep} } \bubble{bubblegray}{sharp~corners=northwest}{black}{\l__ooker_bubbles_last_tl}\par } \end{flushleft} } \ExplSyntaxOff \begin{document} \begin{rightbubbles} Left-aligned gray bubbles (241, 240, 240) with black text Right-aligned green bubbles (103, 184,104) with white text Bubbles only break after a paragraph (equivalent to an enter press when chatting). Long message with multiple lines will be kept in one bubble. Left and right edges are round. \end{rightbubbles} \begin{leftbubbles} Left-aligned gray bubbles (241, 240, 240) with black text Right-aligned green bubbles (103, 184,104) with white text Bubbles only break after a paragraph (equivalent to an enter press when chatting). Long message with multiple lines will be kept in one bubble. Left and right edges are round. \end{leftbubbles} \begin{rightbubbles} Single \end{rightbubbles} \begin{leftbubbles} End \end{leftbubbles} \end{document}
